“Missing” language features: varargs and multistatement lambdas

2,128 views
Skip to first unread message

flying sheep

unread,
Jan 31, 2012, 8:55:24 AM1/31/12
to General Dart Discussion
hi,
i thought about the syntax and found some (imho) oddities:

1. varargs:

it’s no problem to define a constructor to accept an optional List
argument, i know, but defining your own “literals” has its own charm
and is less tedious and more DRY.

instead of new Set.from(['x', 'y']), new Set('1', '2', '3') could be
used.

2. multistatement lambdas

scala does function definitions like that: for functions without
return value, you type def <name> <block>, for functions with one, you
type def <name> = <statement|block>

you have to use block braces for the first one, but can leave them out
for the second (for e.g. getters). in functions returning something,
the return value of the last statement in the control flow is returned
if it is reached, but you can also break out of the control flow by
using the return keyword. i think it’s nice and functional.

i think dart’s lambdas (=>) are odd: they are as powerless as
python’s, but dart allows anonymous functions.

i’s most likely too late to change it, but designating at the
beginning if a function returns something (different than null) and
then returning the last value is better than the C(++) way.

what do you think? will “=>” be viewed like python’s lambda in the
future (useful sometimes, but never fully thought through)? would
varargs be a good idea instead of new constructors for even the
simplest cases?

Dirk Detering

unread,
Jan 31, 2012, 10:39:09 AM1/31/12
to flying sheep, General Dart Discussion


Am 31.01.2012 14:55 schrieb "flying sheep" <truefly...@googlemail.com>:
>
> hi,
> i thought about the syntax and found some (imho) oddities:
>
> 1. varargs:
>
> it’s no problem to define a constructor to accept an optional List
> argument, i know, but defining your own “literals” has its own charm
> and is less tedious and more DRY.
>
> instead of new Set.from(['x', 'y']), new Set('1', '2', '3') could be
> used.
>
> 2. multistatement lambdas
>
> scala does function definitions like that: for functions without
> return value, you type def <name> <block>, for functions with one, you
> type def <name> = <statement|block>
>
> you have to use block braces for the first one, but can leave them out
> for the second (for e.g. getters). in functions returning something,
> the return value of the last statement in the control flow is returned
> if it is reached, but you can also break out of the control flow by
> using the return keyword. i think it’s nice and functional.
>
> i think dart’s lambdas (=>) are odd: they are as powerless as
> python’s,

What do you mean with "powerless"?

>but dart allows anonymous functions.
>
> i’s most likely too late to change it, but designating at the
> beginning if a function returns something (different than null) and
> then returning the last value is better than the C(++) way.
>
> what do you think? will “=>” be viewed like python’s lambda in the
> future (useful sometimes, but never fully thought through)?

What do you mean with "never fully thought through"?
I haven't understood what the concrete critics are.

BTW: AFAIC Scala has the exact same lambda construct, so I am confused by this post.

Colin Putney

unread,
Jan 31, 2012, 12:00:38 PM1/31/12
to flying sheep, General Dart Discussion


On Tue, Jan 31, 2012 at 5:55 AM, flying sheep <truefly...@googlemail.com> wrote:


> i think dart’s lambdas (=>) are odd: they are as powerless as
> python’s, but dart allows anonymous functions.

The "fat arrow" syntax is just sugar for anonymous functions that just return a single expression. Both versions are proper closures. So this:

    c = 1
    (a, b) {return a + b + c}

can also be written
   
   c = 1
   (a, b) => a + b + c

If you want "multistatement lambdas" you have to use the version with braces:

    comparisons = [];
    [3, 1, 2].sort((a, b) {
        comparisons.add([a, b]);
        return a < b
    });

HTH, 

Colin

Bob Nystrom

unread,
Jan 31, 2012, 1:44:29 PM1/31/12
to flying sheep, General Dart Discussion
On Tue, Jan 31, 2012 at 5:55 AM, flying sheep <truefly...@googlemail.com> wrote:
hi,
i thought about the syntax and found some (imho) oddities:

1. varargs:

it’s no problem to define a constructor to accept an optional List
argument, i know, but defining your own “literals” has its own charm
and is less tedious and more DRY.

instead of new Set.from(['x', 'y']), new Set('1', '2', '3') could be
used.

We had varargs (or "rest params" in the lingua of other languages) in Dart for a while. It is handy in a few places (along with its buddy the spread operator). However, function parameter lists are already one of the most intricate corners of the language. In a very small chunk of the grammar, we need to worry about positional parameters, named optional parameters (which may be called by name or position), field initializer parameters, and noSuchMethod's generic support for working with argument lists.

Cramming rest params in there too is pretty hard. (Imagine defining a function that has both optional and rest params and try to figure out what gets bound to what. Now imagine compiling that to JS. Now imagine compiling it to JS and needing to support noSuchMethod).

To keep things as simple as possible at least for now we took them out. They can always return later on once we've got the existing features nice and baked.


2. multistatement lambdas

scala does function definitions like that: for functions without
return value, you type def <name> <block>, for functions with one, you
type def <name> = <statement|block>

you have to use block braces for the first one, but can leave them out
for the second (for e.g. getters).

Yes, we have that in Dart too: both single expression lambdas and multiple statement function expressions. Both, of course, have full access to their lexical closure.
 
in functions returning something,
the return value of the last statement in the control flow is returned
if it is reached, but you can also break out of the control flow by
using the return keyword. i think it’s nice and functional.

Right, this is the piece we don't have. Scala, like most functional languages, doesn't have statements. Everything is an expression, including block bodies. What looks like a statement block is an expression containing a series of expressions. Its result is the result of the last expression. (In other words, it's like the comma operator in C.)

I really like languages that work that way (which includes CoffeeScript, Scala, Ruby, and most languages derived from Lisp or ML). However, most people aren't familiar with expression-oriented languages. C and its derivatives all have a strong statement/expression distinction and that's the most popular paradigm in languages today. Dart follows closely in those footsteps.

In practice, you don't lose that much by having statements: you've got to do an explicit return at the end of some blocks, and you have to use a ternary operator instead of if being an expression.


i’s most likely too late to change it, but designating at the
beginning if a function returns something (different than null) and
then returning the last value is better than the C(++) way.

It may be better from the expressiveness angle but it's less familiar to lots of programmers and unfamiliarity is a tax we're always cautious about having to pay.


what do you think? will “=>” be viewed like python’s lambda in the
future (useful sometimes, but never fully thought through)?

No, I don't think so. For what it's worth, I think Python does the right thing here too. Significant indentation doesn't play nice with nested expressions, which is what you'd be talking about with multiline lambdas there. CoffeeScript does this and I find that corner of its syntax pretty hairy.

Cheers!

- bob

flying sheep

unread,
Jan 31, 2012, 2:40:16 PM1/31/12
to General Dart Discussion
On 31 Jan., 19:44, Bob Nystrom <rnyst...@google.com> wrote:
> We had varargs…

ah, ok, i understand. while i don’t think it’s complicated to use
(python handles it pretty logically), the cross-compiling is an issue,
and the gain not big enough to justify it.

> Most people aren't familiar with expression-oriented languages.

which is sad, since learning haskell changed my coding for the better.
expression-based code is imho just a natural consequence of first-
order functions and closures. a syntax that differentiates between
“value-returning functions” and “purely imperative functions” would
fit a language like JS/dart pretty well.

that being said, i understand why you would rather use traditional
syntax for a language that wants to get traction.

> > Will “=>” be viewed like python’s lambda in the future?

KidsKilla

unread,
Feb 1, 2012, 7:06:16 AM2/1/12
to General Dart Discussion
> > in functions returning something,
> > the return value of the last statement in the control flow is returned
> > if it is reached, but you can also break out of the control flow by
> > using the return keyword. i think it’s nice and functional.
>
> Right, this is the piece we don't have. Scala, like most functional
> languages, doesn't have statements. Everything is an expression, including
> block bodies. What looks like a statement block is an expression containing
> a series of expressions. Its result is the result of the last expression.
> (In other words, it's like the comma operator in C.)
>
> I really like languages that work that way (which includes CoffeeScript,
> Scala, Ruby, and most languages derived from Lisp or ML). However, most
> people aren't familiar with expression-oriented languages. C and its
> derivatives all have a strong statement/expression distinction and that's
> the most popular paradigm in languages today. Dart follows closely in those
> footsteps.

Well, do you think it's a problem for developers to know that anything
in language has a returning value? Anyway, this feature isn't prevent
you from writing an old fasioned style. But there is potentially a
huge boost of language grow with that feature because programs can be
the way more compact.

Bob Nystrom

unread,
Feb 1, 2012, 2:37:32 PM2/1/12
to KidsKilla, General Dart Discussion
On Wed, Feb 1, 2012 at 4:06 AM, KidsKilla <kids...@gmail.com> wrote:
Well, do you think it's a problem for developers to know that anything
in language has a returning value?

It's one more thing to learn when picking up the language. Whenever possible, we try to minimize the amount of new stuff you have to know to be productive in Dart. It's really hard to get people to use a new language and it doesn't take much friction before they just give up entirely. If statements make the language more palatable for some users, that adds value.

Given how closely Dart's syntax mirrors C/C++/Java/C#/JS now, I think it would be particularly confusing if the semantics of something as fundamental as statements were different.

Anyway, this feature isn't prevent you from writing an old fasioned style.

Of course, you can always avoid features you don't like in code you write. The problem is in code you read. If we made everything an expression in Dart it's only a matter of time before you run into code like:

last(List items) {
  if (items.length > 0) items[items.length - 1];
}

That code is going to deeply confuse someone coming from a statement-oriented background because it looks familiar but it also doesn't look like something that would work at all.

But there is potentially a huge boost of language grow with that feature because programs can be the way more compact.

I like not having statements too, but in practice I don't think it makes that much of a code-size difference. Even in languages that don't have statements, many things like variable declarations are still "statement-like". We have => for single-expression method bodies which covers a lot of the simple use cases:

last(List items) => (items.length > 0) ? items[items.length - 1] : null;

- bob

Dirk Detering

unread,
Feb 2, 2012, 12:24:12 AM2/2/12
to Bob Nystrom, KidsKilla, General Dart Discussion

As much as I can follow the argumentation, it is a very small path where you can easily down at one side or the other.

Am 01.02.2012 20:38 schrieb "Bob Nystrom" <rnys...@google.com>:
> Whenever possible, we try to minimize the amount of
> new stuff you have to know to be productive in Dart.

That is a good maxime, but a subjective view of each user if you achieved that or not. It depends on where one comes from.

> It's really hard to get people to use a new language and it
> doesn't take much friction before they just give up entirely.

That is true, but the friction may also exist due to well known but annoying properties taken from the predecessors. Beside that, the decision if a property is a well known and good, a well known and bad, a new but highly appraised or a new but confusing concept is really tough and also subjective.

Sometimes I wish for something like plaedoyers (right word?) for and against features followed by a public voting, to get a better understanding of how the masses think about it. (Well, democracy in language design is not really doable,I know!)

> If statements make the language more palatable for
> some users, that adds value.

This is right. So the question is: Is it more palatable? Would it be really a friction otherwise?

> Of course, you can always avoid features you don't like in code you write. The problem is in code you read. If we made everything an expression in Dart it's only a matter of time before you run into code like:
>
> last(List items) {
>   if (items.length > 0) items[items.length - 1];
> }
>
> That code is going to deeply confuse someone coming from a statement-oriented background because it looks familiar but it also doesn't look like something that would work at all.
>

Right. From an expression perspective mainly because it is incomplete. Where is the else? It *should* be invalid code!

> I like not having statements too, but in practice I don't think it makes that much of a code-size difference. Even in languages that don't have statements, many things like variable declarations are still "statement-like". We have => for single-expression method bodies which covers a lot of the simple use cases:
>
> last(List items) => (items.length > 0) ? items[items.length - 1] : null;
>

The current promises of familiarity may lead to the false impression that there may be no need to learn or develop an idiomatic Dart.
In my eyes it is much easier for a language to communicate a clean concept of idioms when they give the user recognizable advantages, than to communicate familiarity that is not achievable in all respects.
(I only say:  C style type annotation, functions first-class, typing optional ... a weird combination ... born out of "familiarity"?)

Bob Nystrom

unread,
Feb 2, 2012, 4:51:43 PM2/2/12
to Dirk Detering, KidsKilla, General Dart Discussion
On Wed, Feb 1, 2012 at 9:24 PM, Dirk Detering <mail...@googlemail.com> wrote:
> Whenever possible, we try to minimize the amount of
> new stuff you have to know to be productive in Dart.

That is a good maxime, but a subjective view of each user if you achieved that or not. It depends on where one comes from.


Right. There's a certain amount of guesswork involved but we can make statistical statements about groups of users. For example, using begin and end for blocks would be more familiar to Rubyists but less familiar to Java/JS programmers. We can compare the sizes of those respective communities to try to get a rough feel for which side we should lean towards. I don't think anyone would claim this is a perfect science though.
 

That is true, but the friction may also exist due to well known but annoying properties taken from the predecessors. Beside that, the decision if a property is a well known and good, a well known and bad, a new but highly appraised or a new but confusing concept is really tough and also subjective.

Exactly! If we wanted everything to be familiar, we wouldn't make a new language at all. Part of the challenge of being a language designer is deciding when the value of a new feature overrides its unfamiliarity tax.

Sometimes I wish for something like plaedoyers (right word?) for and against features followed by a public voting, to get a better understanding of how the masses think about it. (Well, democracy in language design is not really doable,I know!)

I don't think anyone would want a democracy for deciding language issues but I do think it could be beneficial to have a slightly more formal way of gathering feedback. We may not pick feature X even though 58% of respondents prefer it, but it seems like that would be a useful number to have.
 

> If statements make the language more palatable for
> some users, that adds value.

This is right. So the question is: Is it more palatable? Would it be really a friction otherwise?

That is the question!

> last(List items) {
>   if (items.length > 0) items[items.length - 1];
> }
>
> That code is going to deeply confuse someone coming from a statement-oriented background because it looks familiar but it also doesn't look like something that would work at all.
>

Right. From an expression perspective mainly because it is incomplete. Where is the else? It *should* be invalid code!

No, that code likely would be valid. Just like all functions implicitly return null in Dart, an if expression without an else would likely return null if the condition didn't match. Even if we didn't do that, then this:

 last(List items) {
   if (items.length > 0) items[items.length - 1]; else null;
 }

is still just as confusing to someone coming from a statement-oriented background.
 

The current promises of familiarity may lead to the false impression that there may be no need to learn or develop an idiomatic Dart.

I think optional types, closures, top-level functions and variables, getters, setters, named arguments and operator overloading go a long way towards creating a need for idiomatic Dart.

- bob

Reply all
Reply to author
Forward
0 new messages