Skip to content
This repository has been archived by the owner on Apr 13, 2023. It is now read-only.

let #3853

Closed
CeylonMigrationBot opened this issue Aug 14, 2013 · 31 comments
Closed

let #3853

CeylonMigrationBot opened this issue Aug 14, 2013 · 31 comments

Comments

@CeylonMigrationBot
Copy link

[@gavinking] As Ceylon is gradually moving toward being more expression-oriented and less statement-oriented, let expressions are becoming more and more useful. There's been some explicit discussion of them in #3483 and #3850. I'm opening this issue because this is actually of course a separate, independently useful construct.

The syntax would be something like this:

let (dist = sqrt(x^2+y^2)) [x/dist,y/dist]

Of perhaps, in order to avoid growing a new keyword, like this:

given (dist = sqrt(x^2+y^2)) [x/dist,y/dist]

Note that this feature might let us simplify the syntax of if expressions in #3609, since you could write stuff like this:

let (first = sequence.first) if (exists first) first+1;

I think we should make this one a priority for 1.1.

[Migrated from ceylon/ceylon-spec#747]
[Closed at 2014-11-25 21:22:17]

@CeylonMigrationBot
Copy link
Author

[@gavinking] P.S. If we're considering introducing a new keyword, then that is a decision we should make now before 1.0 goes final!

@CeylonMigrationBot
Copy link
Author

[@tombentley]

that is a decision we should make now before 1.0 goes final!

It's got to be worth reviewing the other features we'd like for 1.1 in case there are other words we'd like to reserve before it's too late.

@CeylonMigrationBot
Copy link
Author

[@gavinking] @tombentley Don't worry, I'm on top of that ;-)

@CeylonMigrationBot
Copy link
Author

[@oehme]
+1

With let I could refactor this:

Complex times(Complex other) => Complex(a*other.a - b*other.b, a*other.b + b*other.a);

To a more Wikipedia-looking definition:

Complex times(Complex other) => let(c = other.a, d = other.b) Complex(a*c - b*d, a*d + b*c);

Without making it a block and introducing two values, which would make it 4 lines of code.

Of course even better would be:

Complex times(Complex(c, d) other) => Complex(a*c - b*d, a*d + b*c);

@CeylonMigrationBot
Copy link
Author

[@gavinking] So shall I reserve let? Speak up, please?

@CeylonMigrationBot
Copy link
Author

[@RossTate] Given that given is already a keyword, I suggest first polling whether that makes sense to use here.

@CeylonMigrationBot
Copy link
Author

[@quintesse] Although let is by far the more common keyword for these kind of situations I would be fine with given. On the other hand I don't think let is a name that gets used very often as a variable or method so it wouldn't necessarily be missed. If i would have to give precedence I'd probably go for given.

@CeylonMigrationBot
Copy link
Author

[@oehme] I would be fine with "given", too.

@CeylonMigrationBot
Copy link
Author

[@gavinking] I very weakly incline toward let, because:

  • it's at least slightly confusing to newcomers if the same keyword means two totally different things,
  • everybody knows what let means, and
  • I have never ever wanted to name a function or value "let".

But honestly I could go either way.

@CeylonMigrationBot
Copy link
Author

[@lucaswerkmeister] I’m not sure I understand the purpose of this. Could you use let in comprehensions like this?

value something = {
    for (datum in data)
        let (result1 = op1(datum), result2 = op2(datum))
            [opX(result1), opY(result2), opZ(result1, result2)]
};

That would certainly be useful.

EDIT: or is that #3483? I’ve skimmed through the conversation, but it seems you discussed a whole lot of other things there as well that’s mostly unrelated…

@CeylonMigrationBot
Copy link
Author

[@gavinking] I have implemented let in the branch named let. It still needs a spec, tests, and an implementation in the backends.

@CeylonMigrationBot
Copy link
Author

[@FroMage] So what's the syntax? I suppose it's a let* which means each new binding sees the previous ones, so it's evaluated in order? As opposed to a standard Scheme let where all new bindings are evaluated in the enclosing scope only, and letrec where each new binding can see every new binding, including the ones after it.

@CeylonMigrationBot
Copy link
Author

[@quintesse] Yes, this is the one that confuses me the most. What does this do anyway:

let (dist = sqrt(x^2+y^2)) [x/dist,y/dist]

It makes a tuple of two elements using the dist binding? It's just that all the examples given seem to be like this, so it almost seems that the [ ] is part of the syntax.

@CeylonMigrationBot
Copy link
Author

[@gavinking]

So what's the syntax?

let (x="hello", y="world") x + " " + y

I suppose it's a let* which means each new binding sees the previous ones, so it's evaluated in order?

Yes, of course.

It makes a tuple of two elements using the dist binding?

Of course.

@CeylonMigrationBot
Copy link
Author

[@quintesse] Ok, so it's something like "let" "(" variable-assignment* ")" expression , where the parens are required even if you don't bind anything.
Edit: it's variable-assignment+ not variable-assignment*, I misinterpreted the parser code.

@CeylonMigrationBot
Copy link
Author

[@FroMage] Why, is it allowed to have no bindings? What's the use-case?

@CeylonMigrationBot
Copy link
Author

[@quintesse] Sorry @FroMage , my mistake, it's actually: "let" "(" variable-assignment+ ")" expression

@CeylonMigrationBot
Copy link
Author

[@gavinking]

Why, is it allowed to have no bindings?

Of course not.

@CeylonMigrationBot
Copy link
Author

[@FroMage] OK, thanks.

@CeylonMigrationBot
Copy link
Author

[@FroMage] Should I do this one for the JVM then?

@CeylonMigrationBot
Copy link
Author

[@quintesse] Ok, with me, I'm not going very fast at the moment with my current issue :/

@CeylonMigrationBot
Copy link
Author

[@tombentley] Go on then, I'll let you have this one.

@CeylonMigrationBot
Copy link
Author

[@FroMage] Haha.

@CeylonMigrationBot
Copy link
Author

[@FroMage] Done on the JVM in the let branch.

@CeylonMigrationBot
Copy link
Author

[@chochos] Done on JS in the let branch as well. But I wanted to add some tests along with the impl and it turns out that the declarations don't see each other... I thought each new declaration would see the previous one like @FroMage mentioned earlier: let (e="K"->1, k=e.key, v=e.item) [v,k] but k and v don't see e.

@CeylonMigrationBot
Copy link
Author

[@gavinking]

I suppose it's a let* which means each new binding sees the previous ones, so it's evaluated in order?

In fact this is not currently working.

@CeylonMigrationBot
Copy link
Author

[@gavinking] @chochos Fixed, I think.

@CeylonMigrationBot
Copy link
Author

[@chochos] Yes, working now! This is why I think it's better to have some of these tests in the language module, even if they're not directly related to the language module itself; those tests are run on both backends.

@CeylonMigrationBot
Copy link
Author

[@gavinking] Branched merged. Done!

@CeylonMigrationBot
Copy link
Author

[@gavinking] Oh, wait, still need a spec!

@CeylonMigrationBot
Copy link
Author

[@gavinking] Spec done, closing!

@CeylonMigrationBot CeylonMigrationBot added this to the 1.2 milestone Nov 14, 2015
gavinking added a commit that referenced this issue Nov 14, 2015
gavinking added a commit that referenced this issue Nov 14, 2015
gavinking added a commit that referenced this issue Nov 14, 2015
quintesse pushed a commit that referenced this issue Nov 14, 2015
The spec used to define some operators via pseudocode let expressions
like this:

    let x=y in e

which, with the introduction of actual let expressions into the
language (#3853), can instead be written as:

    let (x=y) e

rendering the previous syntax not only obsolete, but also confusing; see
for example @PhiLhoSoft on the ceylon-users mailing list:
https://groups.google.com/d/msg/ceylon-users/N3idC2CZQxI/N_-BaNdydzgJ
This was referenced Nov 14, 2015
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants