Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Jens Li
committed
Apr 12, 2013
1 parent
029fa7f
commit 9435acf
Showing
31 changed files
with
89 additions
and
0 deletions.
There are no files selected for viewing
Empty file.
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
|
||
Pattern matching in switch proposal | ||
|
||
Intro | ||
===== | ||
|
||
A very useful feature in many functional languages is pattern matching. This makes it very easy and concise to write some kind of logic that can be pretty hairy to express with normal if:s and switch:s. | ||
|
||
I propose adding pattern matching capabilities to the Fantom switch statement in a way that resemble how it looks in Scala. | ||
|
||
UPDATE: This proposal tries to introduce a unified way of switching on the type and contents of objects, instead of making smaller and more directed changes. | ||
|
||
For a description of the Scala model have a look at the [Programming in Scala]`http://www.artima.com/pins1ed/case-classes-and-pattern-matching.html` book. | ||
|
||
Pattern matching would be added for lists, maps, and the type and fields of objects using the it-block style constructor syntax. | ||
|
||
Example | ||
======= | ||
|
||
This is an example of how it might look in Fantom: | ||
|
||
pre> | ||
class Animal{Animal? parent := null} | ||
|
||
class Turtle : Animal{Int field1 := 1} | ||
|
||
class Frog : Animal{Int field2 := 2} | ||
|
||
Void patternExample(Animal o) | ||
{ | ||
switch (o) { | ||
case Turtle{field2 = 2; parent = Frog{} as par}: | ||
echo("Object pattern. Parent: " + par) | ||
case [1, _ as snd]: | ||
echo("List pattern. Second list elem: " + snd) | ||
case ["key1": 1, "key2": _ as val2] if (val2 > 7): | ||
echo("Map pattern. key2: " + key2) | ||
case 17: | ||
echo("Simple literal") | ||
default: | ||
echo("Default") | ||
} | ||
} | ||
<pre | ||
|
||
The first 'case' branch is chosen if 'o' is a object of type 'Turtle', its 'field2' has value '2', and its field 'parent' has an object of type 'Frog' as its value. The 'par' variable introduced with the 'as' keyword can be used only in that branch. | ||
|
||
If that pattern doesn't match, the list patterns in the second 'case' is tried. It matches if 'o' is a two elem list, with '1' as its first elem and any second elem. '_' is the wildcard, "don't care" pattern. It is bound to the variable 'snd'. | ||
|
||
The third 'case' is a map pattern, checking for the presence of keys '"key1"' and '"key2"' in 'o', that '"key1"' is mapped to '1', and binding the value of '"key2"' to the variable 'key2'. | ||
|
||
The fourth 'case' is a simple expression pattern, which is compared to 'o' with 'equals'. | ||
|
||
|
||
Details of proposal | ||
=================== | ||
|
||
The current switch works by comparing the value of an expression in each 'case' with the objects 'equals' method. This would change so that after each 'case' a pattern is expected instead of an expression. The object that is switched on will be checked for a match against each pattern in turn. | ||
|
||
Simple expressions are valid patterns. They will get evaluated and their value compared with 'equals' in the switch. | ||
|
||
But after the 'case' keyword, list literals, map literals and it-block constructors will be interpreted as patterns, not as expressions creating objects. | ||
|
||
The value that is switched on is checked to see if it matches the structure of the pattern. The 'case' branch associated with the first matching pattern is executed. | ||
|
||
A pattern can be either: | ||
|
||
- A normal expression. This will work like the current switch, the value will be compared by 'equals'. | ||
|
||
- A literal object, it-block constructor style. This will be checked for a matching type, and can check the value of fields of that type with nested patterns. | ||
|
||
- A literal list, with nested patterns for the elements. | ||
|
||
- A literal map, with expressions for the keys and nested patterns for values. | ||
|
||
- The wildcard identifier, '_', which matches all values. This is useful when one wants to introduce new variables without checking their value. | ||
|
||
A pattern can also introduce new variables. That is done with the 'as' keyword followed by a free identifier, written after the pattern. | ||
|
||
A top level pattern can have a guard. It consists of an 'if' followed by a boolean expression. The pattern match if the expression evaluates to 'true'. | ||
|
||
|
||
Scala | ||
===== | ||
The Scala match statement is extendible in a very flexible way with custom extractors. This rimes well with Scalas goal of being extendible with new syntax, but it is complex and potentially bad for readability. The Fantom solution should probably aim for something simpler which solves the large majority of cases. | ||
|
||
|
Empty file.
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.