The main issue is that its hard to parse (int -> int -> int)
>
> LT
R�mi
In the spirit of "everything can change", I'd like to suggest changing function type syntax to be different from function declaration syntax. I'll try to illustrate it on predicates (single-argument functions returning bools), but it is a general problem. A small demonstration program is here: https://github.com/Ladicek/dart-playground/blob/master/function-types.dartDeclaring a function is simple:bool predicate(obj) => ...Easy. You can declare a function-typed parameter of a function in the very same way:void function(something, bool predicate(obj)) => ...This already puzzles me a little: parameter declaration in Dart has the form of Type name, i.e. the type goes _before_ the name, but in case of function-typed parameters, part of the type actually goes _after_ the name. I already caught myself several times thinking about the right syntax when I was writing such thing.But here comes the treason: what if you want to declare a function-typed variable? Intuition might lead tobool predicate(obj);but that's wrong. That is actually a function declaration, but without a body, and this exact syntax already occurs in interfaces. You can either declare the variable as var, omitting the type entirely, or declare it using a typedef:typedef bool Predicate(obj);Predicate predicate;This situation, if I understand correctly, is the very reason for typedefs in Dart. So, by defining another syntax for function types, distinct from function declarations, you would not only gain some more readability, but you could also get rid of typedefs. Not that I'm suggesting to do it, typedefs have their use, but they shouldn't be mandatory for such simple thing.Anyway: how about using something like (param1, param2, ..., paramN -> returnType) for function type? The examples above would look like this:// predicate as a parameter to functionvoid function(something, (obj -> bool) predicate) => ...// predicate as a variable(obj -> bool) predicate;// and with typed parameters:void function(something, (Object obj -> bool) predicate) => ...(Object obj -> bool) predicate;
// and a typedeftypedef (obj -> bool) Predicate;Here are some edge cases:// function without arguments returning bool( -> bool) var1;
// function with single (bool) argument and without defined return type(arg -> ) var2;(bool arg -> ) var3;
// function without arguments and without defined return type( -> ) var4;
These are not particularly nice, but they are quite regular and predictable.I didn't inspect the grammar, so I'm not sure if this syntax would lead to ambiguities, but I suspect that they could be solved. Also, I guess the fat arrow could be used instead of the thin one, I just used it for better distinguishability.But as far as I'm concerned, function type syntax isn't the most important thing here, it's the fact that function declaration syntax and function type syntax should be _different_.
Any thoughts? Does this sound reasonable to you? Should I file an issue?
LT
The main issue is that its hard to parse (int -> int -> int)
// and with multiple parameters:void function(something, (Object a, Object b -> bool) predicate) => >..I want to put a parenthesis after b so badly.
(void -> bool) var1;
(arg -> void) var2;(bool arg -> void) var3;
Why not use this for function declaration as well?
Nice this comes up again. We talked about that in another thread once, where I mentioned the discrepancy between the declaration an the error message that indeed uses the single-arrow syntax for reporting.
And once again the mentioned examples show how badly fits c-style leading type into that concept, most of all when Dart prefers to not only give types but also parameter *names* in HOF parameter:
int outer(int param, int ofun(String somepar, String otherpar))
Vs.
outer(param:int, ofun(somepar:String, otherpar:String):int):int
Vs.
outer(param:int, ofun:(String,String)->int)
I consider function declaration syntax for parameter typing weird.
And once again the mentioned examples show how badly fits c-style leading type into that concept, most of all when Dart prefers to not only give types but also parameter *names* in HOF parameter
outer(param:int, ofun(somepar:String, otherpar:String):int):int
Am 27.01.2012 08:06 schrieb "Ladislav Thon" <lad...@gmail.com>:
> But, this:
>
>> outer(param:int, ofun(somepar:String, otherpar:String):int):int
>
>
> should definitely read outer(param: int, ofun: (somepar: String, otherpar: String -> int)): int, if you ask me.
Indeed. My example which you quoted was a first derivation from the current state. Like the current state it used function declaration as a parameter declaration, only with trailing type syntax.
It was my next step that changed then to typed arrow syntax as parameter type.
What you present is the next step: putting in names again.
But now we have a problem: for the definition of outer you used :
Fname ( parm:parmtype ) : resulttype
For the parameter you used
Pname:(parm:parmtype)->resulttype
Shouldn't the outer be declared as
outer(.....)->int too?
(It's only a thought, I would not prefer that, especially with a following => to separate the body)
Another thought comes to mind: The dartive mix of parameter types and names for higher order params feels discomforting, although I understand the advantage with optional typing.
Perhaps the Haskell way to separate type and declaration is not so wrong here?
What about
outer::(int, (String, String))->int
outer(param, ofun(somepar, otherpar)) => .....
outer(param, ofun(somepar, otherpar)::(int, (String,String))int => ....
Only brainstorming though.
> Type after the name isn't a great win either, all the colons are too distractive, and especially function types can easily get hard to read.
In my eyes they are, especially in a context where type info can be there or not. Now you read
[Type or Name] [Name or nothing] ( [type or name] [name or nothing] )
With trailing type it becomes:
Name [type or nothing] ( name [type or nothing] )
And with colon as a separator it is always clear that you have a type or not.
See: outer(int param, int ofun (String, String))
Both 'String' are not types but parameter names !!! with type dynamic.
Btw: In my eyes the colon belongs to the type, not the name (you know UML?)
Though I would always avoid spaces between name and type, your example would become:
outer(param :int, ofun :(somepar :String, otherpar :String))
Once again: I would avoid the spaces.
>See also http://blog.jetbrains.com/kotlin/2012/01/the-great-syntactic-shift/ and especially http://blog.jetbrains.com/kotlin/2012/01/the-great-syntactic-shift/#comment-238.
I follow Kotlins argumentation. But not Stephen's in all aspects. Beside that, Kotlin doesn't do as a template because it doesn't mix types and names in the fparam declaration.
But now we have a problem: for the definition of outer you used :
Fname ( parm:parmtype ) : resulttypeFor the parameter you used
Pname:(parm:parmtype)->resulttypeShouldn't the outer be declared as
outer(.....)->int too?
>See also http://blog.jetbrains.com/kotlin/2012/01/the-great-syntactic-shift/ and especially http://blog.jetbrains.com/kotlin/2012/01/the-great-syntactic-shift/#comment-238.
I follow Kotlins argumentation. But not Stephen's in all aspects. Beside that, Kotlin doesn't do as a template because it doesn't mix types and names in the fparam declaration.
My personal view is that a clean syntax for function types (as opposed to function *values*, i.e., function declarations and expressions) would be attractive.
Mainstream syntax makes that difficult.
Thinking about the syntax some more (I admit that my original suggestion with the arrow is strange at least), what about just changing the current order? Instead of
void function(something, bool predicate(obj)) {...},
what about
void function(something, bool(obj) predicate) {...}?
Variable declaration would look like
bool(obj) predicate;
and a typedef (if we decide to keep them)
typedef bool(obj) Predicate;
Hmm, not sure it would work when the return type is omitted:
void function(something, (obj) predicate) {...}
(obj) predicate;
typedef (obj) Predicate;
That's weird. It's difficult indeed...
LT
Am 29.01.2012 12:03 schrieb "Ladislav Thon" <lad...@gmail.com>:
>
> Thinking about the syntax some more (I admit that my original suggestion with the arrow is strange at least), what about just changing the current order? Instead of
>
> void function(something, bool predicate(obj)) {...},
>
> what about
>
> void function(something, bool(obj) predicate) {...}?
I think what we need is a stress list of different constructs each being a showcase for a specific situation. Then we can check each syntax proposal against this list. The list must include:
* function with parameter of type A->B
* same with type A,B,C->D
each of the forementioned with only parameter names (like now in Dart)
* same as before plus parameter types
* function returning a function type
* use a generic type for each type param above
Ladislav, how would the following function read following your proposal, without and with the regarding param types:
(A, B->C) -> (A->C) ?
This being a typical functional construct, I consider it unreadable under the current typing rules.
> (A, B->C) -> (A->C) ?
>
> This being a typical functional construct, I consider it unreadable under the current typing rules.
D'oh, surely that should have been:
((A,B)->C) -> (A->C)
I think what we need is a stress list of different constructs each being a showcase for a specific situation. Then we can check each syntax proposal against this list. The list must include:
* function with parameter of type A->B
* same with type A,B,C->D
each of the forementioned with only parameter names (like now in Dart)
* same as before plus parameter types
* function returning a function type
* use a generic type for each type param above