In Scala they have this nifty pattern matching system that solves unpacking, multiple return values, and tree walking using pattern matching.
In python they have multiple return values using tuples and also allow you to unpack tuples passed as a parameter.
Personally I really like multiple return values, and miss them when they're not there. I really enjoyed using the pattern matching system in Scala for control flow (i.e. None vs Some, empty list vs non-empty list, PlusNode vs MinusNode).
I bumped into a previous discussion on the subject here and it got me thinking a bit about it and I think this would be very cool to have something like this in Fantom.
In the ideal world you could pattern-match and unpack many types of things - regular expression matches, XML, and other data structures come to mind.
By tying pattern matching and unpacking to control flow as in Scala, you avoid the need to try/catch for a failed "unpacking" as in Python where if they return the wrong number of results you get an exception.
One way to structure unpacking and pattern matching might be as a kind of function call - the unpacked bits are passed as parameters. The parameter list of the function is declared as a pattern at the same time creating what they call a "partial" function in Scala:
bla.multipleReturn() ~== |[a,b]| { ... } // unpack parameter to vars a,b
bla.matchMe() ~== |[a,"expected"]| { ... } // only works if second item == "expected"
bla.matchMe2() ~== |[Str,Int]| { ... } // only works if we get a Str and Int
In Scala if a partial function fails to match I believe it throws an exception, but they generally wrap the partial function call in a construct that eats this exception and tries the next alternative instead. Could be something like:
bla.matchMe() ~== oneOf(|Str|{ ... it's a Str }, |Int| { ... it's an Int }, |Obj| { anything else...});
When it comes to tree walking and other kinds of control flow using pattern matching you want to be able to "match" and "unpack" somewhat arbitrary data structures. I think this gets a bit tricky - the "ideal" is that you can match like:
bla.matchMe() ~== |Foo(a,b,c)|{ ... } // Unpack a Foo()
The challenge there is that it can be quite tricky to concretely determine how to translate this lovely looking syntax into some assignments. The writer's intention would be assign values to a,b,c such that constructing Foo with parameters a,b,c would (more or less) give the object being unpacked.
Actually determining this would require the compiler to peek into the constructor for Foo and reverse-engineer which fields those values were stuck into - if any.
In Scala they get around this by restricting pattern matching only to special "case classes" whose constructor parameters are always assigned to same-named fields. Thus it is very clear how constructor parameters relate to fields in the object.
You could explicitly list the fields being matched/unpacked, like:
Or something like that where you're explicitly specifying the fields.
It may be that this pattern matching thing requires too much contortion to fit into an imperative OO language like Fantom... even in Scala they kind of shoe-horned it in with "case classes". In Fantom const classes are similar but don't have the same constructor system that makes it easy to map the constructor parameters to fields when unpacking the object.
dobesvWed 1 Feb 2012
For multiple return values I think probably just using arrays should be fine - arrays are already used for constructing parameter lists and they have a built-in syntax.
So to return multiple return values:
return [a,null];
To unpack them:
[a,null] := foo()
Or something like that. The main can of worms with using assignment to unpack is what to do if the function returns something that doesn't have enough values, or has too many. But it does look and feel nice.
andyWed 1 Feb 2012
Alot of good info here @dobesv. I use anonymous objects all over the place in JavaScript - so I have long wanted to see something like in Fantom as well. Some thorny issues there, but I think they would solve alot of problems surrounding this space elegantly.
I'm not a "Scala-er", so don't have any experience with "unpacking" - but that looks like an interesting workaround to the tuple problem if we used Lists as the return type. Of course you have the new problem of syntax support.
Good ideas to mull on here.
mikeThu 2 Feb 2012
There was a good thread about tuples and multiple return values a while back, including some discussion of other languages that scala borrows from, like Haskell and ML:
I think decomposition and multiple would be a great addition to fan. Brian suggested in that thread that we could figure out how to support decomposition of Lists as a substitute for "real" tuples. That would be pretty easy to implement (I think), and probably do a fair amount of what people would use it for.
However, it would be interesting to explore how fantom might support tuples via generating some kind of synthetic Type at compile time. Like @andy said though, it would be a thorny change.
dobesvThu 2 Feb 2012
I suppose when it comes to multiple return values a reasonable approach would to directly support multiple values in the same way parameters are supported directly. This doesn't allow you to "store" those multiple values into a typesafe Tuple but would allow type checking on the return if you read the multiple return values directly, i.e.:
a, b := foo.multipleReturn(); // a, b automatically have the right type
Looks like this is how the did it in Go: http://golang.org/doc/effective_go.html#multiple-returns
One advantage of this approach compared do "unpacking" a list or tuple is that it is easier to ignore "extra" return values because the compiler will just fill in the first however many return values into your provided variables and ignore the rest. When you return a tuple if the caller only wants the first return value they'll still have to "unpack" that first value somehow. This also gives functions the option to add additional return values later without breaking their existing type contract, as code already written expecting a single return value can automatically ignore any extra return values.
dobesvThu 2 Feb 2012
@andy - in Scala they call it pattern matching, I suppose. In Python they'd call it unpacking tuples, but the python tuples are of course not type safe in any way, basically just an array.
dobesv Wed 1 Feb 2012
In Scala they have this nifty pattern matching system that solves unpacking, multiple return values, and tree walking using pattern matching.
In python they have multiple return values using tuples and also allow you to unpack tuples passed as a parameter.
Personally I really like multiple return values, and miss them when they're not there. I really enjoyed using the pattern matching system in Scala for control flow (i.e. None vs Some, empty list vs non-empty list, PlusNode vs MinusNode).
I bumped into a previous discussion on the subject here and it got me thinking a bit about it and I think this would be very cool to have something like this in Fantom.
In the ideal world you could pattern-match and unpack many types of things - regular expression matches, XML, and other data structures come to mind.
By tying pattern matching and unpacking to control flow as in Scala, you avoid the need to try/catch for a failed "unpacking" as in Python where if they return the wrong number of results you get an exception.
One way to structure unpacking and pattern matching might be as a kind of function call - the unpacked bits are passed as parameters. The parameter list of the function is declared as a pattern at the same time creating what they call a "partial" function in Scala:
In Scala if a partial function fails to match I believe it throws an exception, but they generally wrap the partial function call in a construct that eats this exception and tries the next alternative instead. Could be something like:
See also Scala's extractor objects at http://www.scala-lang.org/node/112
dobesv Wed 1 Feb 2012
When it comes to tree walking and other kinds of control flow using pattern matching you want to be able to "match" and "unpack" somewhat arbitrary data structures. I think this gets a bit tricky - the "ideal" is that you can match like:
The challenge there is that it can be quite tricky to concretely determine how to translate this lovely looking syntax into some assignments. The writer's intention would be assign values to a,b,c such that constructing Foo with parameters a,b,c would (more or less) give the object being unpacked.
Actually determining this would require the compiler to peek into the constructor for
Foo
and reverse-engineer which fields those values were stuck into - if any.In Scala they get around this by restricting pattern matching only to special "case classes" whose constructor parameters are always assigned to same-named fields. Thus it is very clear how constructor parameters relate to fields in the object.
You could explicitly list the fields being matched/unpacked, like:
Or something like that where you're explicitly specifying the fields.
It may be that this pattern matching thing requires too much contortion to fit into an imperative OO language like Fantom... even in Scala they kind of shoe-horned it in with "case classes". In Fantom const classes are similar but don't have the same constructor system that makes it easy to map the constructor parameters to fields when unpacking the object.
dobesv Wed 1 Feb 2012
For multiple return values I think probably just using arrays should be fine - arrays are already used for constructing parameter lists and they have a built-in syntax.
So to return multiple return values:
To unpack them:
Or something like that. The main can of worms with using assignment to unpack is what to do if the function returns something that doesn't have enough values, or has too many. But it does look and feel nice.
andy Wed 1 Feb 2012
Alot of good info here @dobesv. I use anonymous objects all over the place in JavaScript - so I have long wanted to see something like in Fantom as well. Some thorny issues there, but I think they would solve alot of problems surrounding this space elegantly.
I'm not a "Scala-er", so don't have any experience with "unpacking" - but that looks like an interesting workaround to the tuple problem if we used Lists as the return type. Of course you have the new problem of syntax support.
Good ideas to mull on here.
mike Thu 2 Feb 2012
There was a good thread about tuples and multiple return values a while back, including some discussion of other languages that scala borrows from, like Haskell and ML:
http://fantom.org/sidewalk/topic/224
I think decomposition and multiple would be a great addition to fan. Brian suggested in that thread that we could figure out how to support decomposition of Lists as a substitute for "real" tuples. That would be pretty easy to implement (I think), and probably do a fair amount of what people would use it for.
However, it would be interesting to explore how fantom might support tuples via generating some kind of synthetic Type at compile time. Like @andy said though, it would be a thorny change.
dobesv Thu 2 Feb 2012
I suppose when it comes to multiple return values a reasonable approach would to directly support multiple values in the same way parameters are supported directly. This doesn't allow you to "store" those multiple values into a typesafe Tuple but would allow type checking on the return if you read the multiple return values directly, i.e.:
a, b := foo.multipleReturn(); // a, b automatically have the right type
Looks like this is how the did it in Go: http://golang.org/doc/effective_go.html#multiple-returns
One advantage of this approach compared do "unpacking" a list or tuple is that it is easier to ignore "extra" return values because the compiler will just fill in the first however many return values into your provided variables and ignore the rest. When you return a tuple if the caller only wants the first return value they'll still have to "unpack" that first value somehow. This also gives functions the option to add additional return values later without breaking their existing type contract, as code already written expecting a single return value can automatically ignore any extra return values.
dobesv Thu 2 Feb 2012
@andy - in Scala they call it pattern matching, I suppose. In Python they'd call it unpacking tuples, but the python tuples are of course not type safe in any way, basically just an array.