Re: Expression-local variables and 'let'
Daniel Bonniot <[email protected]>
| Newsgroups | gmane.comp.lang.nice.general |
|---|---|
| Message-ID | <[email protected]> |
>Yes, but what about the following?:
> val x = foo() in bar(x, x > 0);
> bar(val x = foo(), x > 0);
>
>You save five characters (again, one is a space). Do you really think that the
>second line is more readable?
>
The foo/bar names might confuse the issue, let's rename to a concrete
example (with the same underlying case). Let's say we are writing a
personal money management app, and we want to display the current
balance (not sure if that's the right word, I mean the amount of money,
which could be positive or negative), putting a warning (red color or
whatever) if the balance is negative:
val balance = currentBalance() in display(balance, warn: balance < 0);
display(val balance = currentBalance(), warn: balance < 0);
Yes, I think the second one is more readable. The first thing you see is
display, so you know straight away what we are trying to do, while in
the other version it's burried deep down.
If we translate into english, they become respectively.
Let's call balance the current balance. Now, display that balance, and
warn the user if that balance is negative.
vs
Display the balance which is the current balance, and warn the user if
that balance is negative.
The first version is more complex: it starts by posing a binding, and
then goes on with the main part. I think that's akin to first proving a
lemma when what you want is to prove a certain theorem. If the lemma is
complex, it's much better, because you divided the proof into smaller
parts that are easier to grasp. But if the lemma is trivial, then this
only leads to added complexity, because the structure is more complex. I
think the same goes here: if the value bound to is complex, you gain in
clarity by defining it earlier.
With a less serious example: I would say "There is this person who is
the brother in law of the boss of my wife's cousin. Well, i'm going to
play music with him at his place", but I wouldn't say "There is this
person who is my father. Well, i'm going to play music with him at his
place", but "I'm going to play music with my father at his place" (in a
program, you would write "at my father's place", because there is no
implicit binder like it/him/her, unless you program in perl ;-)
>I think the first line is notably more readable
>because the declaration/initialization of x is clearly seperated from the usage
>of its value,
>
Which is important if that declaration is complex, agreed.
>and also it makes the order of execution explicit.
>
Order of execution is specified in Nice (from left to right), so it's
not less explicit. (the val would be imporant in OCaml were the order is
unspecified).
>For even more
>readability, you can break the first line logically into two. You can't do that
>with the second one.
>
>
Yes, it won't be the second one anymore, you can do it with a classical
binding. You will say "but then the scope is not respected, unless you
use additional braces", which is true. However, I think the scope issue
is mainly important when combined with the foo(int x = ...) { ... },
because there there are braces, and you really feel like x should only
be visible inside those braces that you wrote anyway (consistently with
'for' and 'using'). For "normal" method call in a block, it's a
well-established fact that you can declare a variable inside the block,
and it extends until the end of the block. I'm not saying it's ideal,
but it's not something horrible either.
>>>What does the following mean? I assume it passes two arguments to bar but
>>>it could also be misread as declaring two arguments:
>>>
>>> bar(int x = 1, y = 0);
>>>
>>>
>>>
>>>
>>I would say you assume right. You will get a 'unused variable' for x,
>>and y needs to be declared previously.
>>
>>
>
>I think that is not intuitive, considering that we can do:
> int x = 1, y = 1;
> bar(x);
>
>
I don't think this is a practical problem. If you write:
bar(int x = 1, y = x + 1) // so there is no warning about x unused
what could you possibly mean except passing two arguments to bar?
>You have to have seperate grammar constructs "single variable declaration" (for
>parameters) and "variable declaration" (for the general case).
>
That's a minor annoyance, especially given that their semantics
scope-wise is different.
>Also, you can't
>say that this is a generalization of the syntax for for(...) because you can
>declare multiple variables at once in a for loop:
>
> for (int x = 1, y = 0;;);
>
>
You're right. That's because in for the first part is simply about
initialization, the values are not "arguments" of for. So what we are
generalizing is the idea of introducing bindings inside another
expression or statement, not only as a statement itself.
It's a proper generalization of 'using', still. It also generalizes
'while' if I'm not mistaken, since you can then also implement it as a
user-defined function.
>>If you need to define several variables in a limited scope, you can
>>already use the C-syntax idiom (should I say Algol?):
>>
>>{
>> let x = ...;
>> let y = ...;
>> ...
>>} // scope ends for x and y
>>
>>
>
>I think everybody hates that syntax, which is why nobody ever uses it. let...in"
>is an improvement in both the single-variable and multi-variable cases.
>
>
Yes, it's rarely used, but I'm not sure it's because the syntax is ugly.
It can also be because methods should be short anyway, so you probably
write a helper method instead of creating a nested scope. And for what's
left, the extra trouble is probably not worth the extra scoping you get
(if a method is 3-5 lines, then usage is easily spotted).
>>>>Expression-local variables basically take this special handling, and
>>>>generalize it to a general-purpose construct. This means that the new
>>>>construct is not alien, it's a generalization. This also means you can
>>>>
>>>>
>
>This is not true, see the above comparison of "bar(int x = 1, y = 0);" and
>"for (int x = 1, y = 0;;);"
>
>
As I said, it does not allow you to implement for in user code. What I
mean is that this scoping is building on an existing tradition, it's not
completely alien.
>I prefer "let" over "val" since it is easier to distinguish from "var" than
>"val" is.
>
>BTW, did you know that "val" and "var" are written and pronounced the same in a
>few languages, including Japanese ("l"="r" in Japanese; e.g. "erection" and
>"election" are written and pronounced the same).
>
>
I hadn't though about that!
>>It's hard to please everyone. Who will come up with the magic solution
>>to please them all? ;-)
>>
>>
>
>Main Entry : let..in
>Pronunciation: 'let 'in
>Etymology : ML
>Definition : magic solution ;)
>
>
I'm not convinced yet, unfortunately.
Daniel
-------------------------------------------------------
SF.Net is sponsored by: Speed Start Your Linux Apps Now.
Build and deploy apps & Web services for Linux with
a free DVD software kit from IBM. Click Now!
http://ads.osdn.com/?ad_id=1356&alloc_id=3438&op=click