It allows for code like:
table.withValue("key", value):
echo "value is ", value
do:
echo "key is not in table"
Personally I've been arguing for the removal of the first use case for years now. For the second we could certainly do with a better syntax:
table.withValue("key", value):
echo "value is ", value
else:
echo "key is not in table"
IIRC me and @Araq discussed the above recently. Maybe it's time I create a PR :)
There is also probably a whole lot of quote do: code out there. While it may not be the most robust kind of macro metaprogramming, that general area is one of Nim's very distinctive features.
algorithm.sort docs still direct users to use do instead of a (proc(): int =) lambda syntax. Sorting is very common. I haven't surveyed the nimbleverse, but I'd bet this construct comes up at least dozens of times. It is plausibly common in "dark"/unsurveyable code.
Besides being confusing about whether the else: pairs with an if ...: or template/macro call, another downside to else: is that it is more alternative/binary in its plain English meaning. withValue is just one example. There is nothing to say that you only have 2 code blocks (vs. 3 or 4..) OR that these blocks are not "and-y"/"additive" like "phase1", "phase2". The word "do" is more neutral in this regard.
@juancarlospaco - ok, but there are literally 1000s of calls to quote do: in the nimbleverse alone. So, we probably can never get rid of it, but that doesn't mean we cannot make it better.
@dom96 - The easy path here might be to just allow do to accept optional parameter names. We could call them, say named do calls. If you got dot-call syntax working for these calls you could write:
table.withValue(key, value):
echo "found ", value
missing.do:
echo key, " missing!"
which I think looks pretty nice. Even better than "else" since "missing" is more specific.
This also generalizes to >2 code-block parameters naturally. Why, it can even be translated to the same AST as the named parameter call syntax, not even breaking macros analyzing template calls (probably). This one aspect might be a little wonky in that there is no way to name the argument for the one param slot going after the first :. TBH, that singular slot is already special-cased anyway.
If there is something that "feels more like an else" just call the parameter stropped-else or maybe orElse and either way readers distinguish it from the keyword. Then it reads orElse.do: .... Naming convention clearly replaces "syntax". (Even the non-dotCall do(clause): ... is already nicer in some ways since it allows "what you are doing" to be written out.)
I think a real benefit is simplifying Nim.
Costs vs benefits. The costs are high and do is only syntax so you don't simplify the language a whole lot. I'd rather throw away Nim's effect system. ;-)
but if someone is passionate enough to create a PR which deprecates it and introduces the syntax above would you complain?
Yes I would.
but I'm not sure if that's appropriate for a language construct.
I think it's completely acceptable. Esp for alexeypetrushin.
Regarding quote do, I see no reason why the do is necessary for this. Still waiting for someone to explain why it uses do. Why can't quote just work?
Regarding @yglukhov's examples, personally I think the proc syntax is perfectly good, your style just needs a tweak :)
foo(a, b,
proc (c, d: int): int =
# Some body here
return c + d
)
But I would say that most of the time if you're writing such code you're already on the way to moving the proc out on to the top-level. If you need a short lambda then you're better off using => so I would avoid inline proc defintions like those anyway.
This is the same old problem — Nim doesn't have backward type inference. The => macro does argument type “inference” in a hacky way by making the function generic, but I'm not sure if that's appropriate for a language construct.
Aha... it explains this mystery. I was always wondering why sugar - a key and one of the most important Nim features, is not in the language itself. Why there's reluctance to include it into the language itself. I knew about backward type inference limitation, but I thought that function arg infer is some special case that works, as it's clearly evident by sugar. And it was really strange to see why it works for sugar but not for do block, as conceptually both are pretty much same thing.
Now I see why it is so :). Because it's a hack that doesn't look good enough to be included into the language. But that's a sad news. Type infer, at the very least for anonymous functions, is very useful and important feature...
Now I see why it is so :). Because it's a hack that doesn't look good enough to be included into the language. But that's a sad news. Type infer, at the very least for anonymous functions, is very useful and important feature...
I dunno, I wouldn't call the => itself a hack, it uses what the the language already provides. Namely the auto type.