# single-line function declarations #442

Closed
opened this Issue Oct 24, 2012 · 20 comments

Projects
None yet
5 participants
Owner

### gavinking commented Oct 24, 2012

 This is something that came up in tangential discussions in #363 and #377. Currently we let you write: ``````function intRange(Integer from, Integer to) = Range; `````` or ``````value intRange = Range; `````` both of which define the function `intRange()` by reference, making `intRange` essentially an alias for `Range`. This was something I settled on a very long time ago, without it ever having been exposed to much discussion. I'm now more and more inclined to think that this is not the best way to go. I think we should instead give you the choice between: ``````function intRange(Integer from, Integer to) = Range(from, to); `````` and ``````value intRange = Range; `````` i.e. the parameters of the function would be in scope on the RHS of `=` and the type of the RHS expression would be expected to be the return type of the function, not the callable type of the function. This would: give you a lot more flexibility, allowing shit like: ``````function intRange(Integer to) = Range(0, to); function sqr(Float x) = x*x; class IntRange(Integer to) = Range(0, to); `````` Indeed, `= something;` would now just mean `{ return something; }`. be much more consistent with the way type alias declarations work currently, where the type parameters are in scope on the RHS (but not the ordinary parameters, curiously, which would be fixed under this proposal). be consistent with the traditional notation in mathematics and, I think, usually more readable. simply look a lot more symmetric and "balanced". The only subtle thing that I can think of here is with forward declaration and named arguments. Currently, the following things are natural: ``````//forward declaration function intRange(Integer from, Integer to); intRange = Range; //named arg void run(Progress p) { ... } void repeat(void do(Progress p)) { ... } repeat { do = run; }; `````` Now, that seems, initially to clash with the new syntax. But not if we let you write the following as well: ``````//forward declaration function intRange(Integer to); intRange(Integer to) = Range(0, to); //named arg void run(Progress p) { ... } void repeat(void do(Progress p)) { ... } repeat { do(Progress p) = run(p); }; `````` In fact, this seems to work out pretty neatly (assuming it can be easily parsed). Indeed, given this new syntax `repeat { do(Progress p) = run(p); };`, we might wind up just simplifying the whole syntax of named argument lists!
Member

### ikasiuk commented Oct 24, 2012

 What about the `=>` notation proposed in #377 (see comment #377 (comment))? This seems closely related to the syntax proposed here. Do you consider allowing both, or is the `=>` notation off the table then?
Owner

### gavinking commented Oct 24, 2012

 This would be instead of introducing `=>`. Essentially I'm proposing that the semantics of `=>` be used whenever we have an `=` after a parameter list. There is one major advantage that `=>` has: it lets you define lazy getters: ``````String name => firstName + ' ' + lastName; `````` But I guess we could achieve the same effect with an annotation: ``````lazy String name = firstName + ' ' + lastName; `````` (Or something.) Do you consider allowing both, or is the `=>` notation off the table then? I'm trying to avoid introducing `=>` because It's very slightly cryptic (though with its popularity in newer languages, increasingly less so) It would give us three syntaxes for defining a function instead of two.

### gavinking added a commit that referenced this issue Oct 26, 2012

 gavinking `solution for immediate problem in #442` `e905a41`
Owner

### gavinking commented Nov 2, 2012

 we might wind up just simplifying the whole syntax of named argument lists! So I want to go a little further down this path. But first I need to bring up a missing feature of named argument lists that we're going to need when we get up to using them to build user interfaces. What we need is the ability to declare a named value inside a named argument list, and access that value "further down the tree". For example: ``````Grid { value text = Text(); Cell { Label("Name: "), text }, Cell Button { label = "Greet"; onClick(Click click) = sayHello(text.value); } } } `````` Given the current syntax for named arg lists, the line `value text = Text();` would be interpreted as an argument to a parameter named `text` of `Grid`, so we would need some special annotation or some shit to distinguish that this is just an ordinary lexically-scoped declaration. But if we can now define functional arguments using the new syntax proposed above, i.e. ``````arg(Param param) = expression(param); `````` Then perhaps it's not as important to be able to do this anymore: ``````Button { label = "Greet"; function onClick(Click click) { sayHello(text.value); } } `````` And it would be OK to force you to use the `actual` annotation to distinguish "new" local declarations from argument functions: ``````Button { label = "Greet"; actual function onClick(Click click) { sayHello(text.value); } } `````` Note that this would be extremely consistent with how this stuff works for `formal` members and refinement! (We interpret a specification statement as refinement, or require you to annotate the declaration `actual`.) Thoughts?
Owner

### gavinking commented Nov 2, 2012

 i.e. what I'm saying is you could write either: ``````Grid { value text = Text(); Cell { Label("Name: "), text }, Cell Button { label = "Greet"; onClick(Click click) = sayHello(text.value); } } } `````` or: ``````Grid { value text = Text(); Cell { Label("Name: "), text }, Cell Button { label = "Greet"; actual function onClick(Click click) { sayHello(text.value); } } } } ``````
Owner

### gavinking commented Nov 2, 2012

 P.S. Of course, you would also be able to use the syntax for refining `formal` methods: ``````abstract class X() { shared formal Float x; shared formal Float y(Float z); } class Y() extends X() { x = 2.0; y(Float z) = z**x; } `````` That's going to be really convenient.
Member

### ikasiuk commented Nov 2, 2012

 There's one thing that strikes me here: how increasingly similar named argument invocations and class bodies are getting. And especially when considering the planned ad-hoc refinement with named arguments (interface instantiation) it seems that a named argument invocation (of a type) basically is an inline object declaration. I think we should seriously explore if there is a way to merge the syntax of named arguments with that of object bodies.
Owner

### gavinking commented Nov 2, 2012

 FTR, I have always considered it a strong goal that they should be very similar, syntactically and semantically. On Nov 2, 2012 4:15 PM, "Ivo Kasiuk" notifications@github.com wrote: There's one thing that strikes me here: how increasingly similar named argument invocations and class bodies are getting. And especially when considering the planned ad-hoc refinement with named arguments (interface instantiation) it seems that a named argument invocation (of a type) basically is an inline object declaration. I think we should seriously explore if there is a way to merge the syntax of named arguments with that of object bodies. — Reply to this email directly or view it on GitHubhttps://github.com/ceylon/ceylon-spec/issues/442#issuecomment-10017503.
Owner

### FroMage commented Nov 3, 2012

 function intRange(Integer from, Integer to) = Range(from, to); I find that confusing because I get the impression that `intRange` is assigned the result of invoking `Range(from, to)`. I understand that this is more in line with class aliases, but for some reason in the case of class aliases I don't have the same impression that the RHS constructor is invoked when defining the alias.
Owner

### FroMage commented Nov 3, 2012

 Regarding allowing local variables in named-param calls, I find it pretty confusing to read. Not only that but if we suddenly require `actual` annotations in there for regular params, it gets heavy. I'd rather have a `let` expression, but even that I'm not really fond of adding at this point. I think we should wait until the need for something like that arises. I haven't had it yet.
Owner

### gavinking commented Nov 3, 2012

 I think we should wait until the need for something like that arises. I haven't had it yet. You will need it the very second you first try to write a user interface in Ceylon.
Owner

### FroMage commented Nov 3, 2012

 I never got that idea (yet). I am on the other hand pretty sure that I'd do this sort of trick in an HTML template: ``````html{ body{ a{ if(userIsAdmin){ id="mainLink"; } href = "..."; } ... a{ if(!userIsAdmin){ id="mainLink"; } href = "..."; } } } ``````
Owner

### gavinking commented Nov 5, 2012

 I have implemented the first step of this: making stuff like the following work: ``````function sqrt(Float x) = x**0.5; `````` And wow, updating the tests, I realize I like this syntax soooo much better!
Owner

### gavinking commented Nov 6, 2012

 The following is now essentially working: ``````function sqrt(Float x); sqrt(Float x) = x**0.5; `````` Pretty cool :-)
Member

### ikasiuk commented Nov 6, 2012

 There's something I don't like about this: ``````Float f() { return x*x; } Float f() = x*x; Float f = x*x; Float f { return x*x; } `````` One of these behaves different than the others, and I find that not very obvious. That was the big advantage of `=>`: it makes the difference immediately clear. Also, I could imagine that getters would be a typical case where the one-line syntax would be useful because getters are often very simple. But as far as I can tell there's currently no way to apply that syntax to getters, isn't it?
Owner

### gavinking commented Nov 6, 2012

 @ikasiuk I agree, it's the one downside of this, and as mentioned above, it's likely we'll want to add some kind of `lazy` annotation or something...
Member

### tombentley commented Nov 8, 2012

 I used to be able to write ``````Callable> f { throw;} Integer foo(Boolean b) = f; `````` but this is no longer considered well-typed. I guess a `lazy` annotation might let me write this, but what I find really surprising is that by deferring the assignment ``````Callable> f { throw;} Integer foo(Boolean b); foo = f; `````` it suddenly becomes well-typed. Is that a bug in the current implementation, or a "feature"?
Owner

### gavinking commented Nov 8, 2012

 Is that a bug in the current implementation, or a "feature"? That's a feature. You're assigning a value of type `Callable>` to a value of the same type. Of course the following is not well-typed: ``````Callable> f { throw;} Integer foo(Boolean b); foo(Boolean b) = f; ``````

Closed

Owner

### gavinking commented Nov 16, 2012

 This feature has been implemented: for declarations in ordinary blocks, and for callable parameters. FTR, @FroMage and @emmanuelbernard talked me into the fat arrow syntax `=>`. So, for example, it is: ``````void tenTimes(String f(Integer i) => i.string) => print(", ".join(for (i in 0..10) f(i))); `````` To finish off this work, we need to do #466. We also need to think some more on my idea above: #442 (comment)

Owner

### quintesse commented Nov 16, 2012

 What does it mean to have it in the parameter? Is it the default value?
Owner

### gavinking commented Nov 16, 2012

 Is it the default value? Of course.

Closed