Excellent! Lots of good tips. The `with` syntax is new to me, but it looks useful for dealing with lots of subfields. Its also a good point that while Nim looks like Python, it very much isn't. Nim is overall much better designed from a computer science perspective with saner scoping rules, etc, IMHO. That means that while Nim as a language is relatively complex, overall its easier to work with than C++ or even Pytho…
https://dlang.org/spec/statement.html#WithStatement D also has withs. Definitely in the "not necessary but nice to have" category of features, particularly when implementing state machines (i.e. statment soup)
For this same reason I really dislike that in C++ you can just implicitly drop the "this->" to target class members. You can never tell at a glance what "foo = blah" does if you don't know whether "foo" is a member of "this" or not.
I think your page demonstrates what I mean in the "nested WithStatement" example:
Foo foo;
Bar bar;
Baz baz;
f(); // prints "f"
with(foo)
{
f(); // prints "Foo.f"
with(bar)
{
f(); // prints "Bar.f"
with(baz)
{
f(); // prints "Bar.f". `Baz` does not implement `f()` so
// resolution is forwarded to `with(bar)`'s scope
}
}
with(baz)
{
f(); // prints "Foo.f". `Baz` does not implement `f()` so
// resolution is forwarded to `with(foo)`'s scope
}
}
with(baz)
{
f(); // prints "f". `Baz` does not implement `f()` so
// resolution is forwarded to `main`'s scope. `f()` is
// not implemented in `main`'s scope, so resolution is
// subsequently forward to module scope.
}
WiI get that sometimes it can cut on a lot of repetition, but I think I would be fine if the syntax was more explicit while still avoiding repetition, for instance:
with (some_object) {
.some_member = 1;
.some_other = 4;
not_a_member = .some_method();
}
And beyond that make it non nestable (i.e. only the first level of "with" is taken into account) to avoid the situation above with complicated overloading.In my experience that would account for 99% of uses of `with` while making the code a lot more readable without requiring a lot of context to make sense of it.
Although frankly even that might arguably overkill, for dynamic languages or ones with type inference you might as well just do something like:
{
let v = &mut some_annoyingly.long.thing();
v.foo = bar;
v.baz();
}
It's almost the same amount of typing and you don't need any magic.