[Issue 596] Support array, arrayliteral and struct in switch and case
https://issues.dlang.org/show_bug.cgi?id=596 Andrei Alexandrescu changed: What|Removed |Added Status|ASSIGNED|RESOLVED Resolution|--- |LATER --- Comment #16 from Andrei Alexandrescu --- Will close this. If anyone is interested a DIP would be the appropriate vehicle. --
[Issue 596] Support array, arrayliteral and struct in switch and case
https://issues.dlang.org/show_bug.cgi?id=596 Andrei Alexandrescu and...@erdani.com changed: What|Removed |Added Version|unspecified |D2 --
[Issue 596] Support array, arrayliteral and struct in switch and case
https://issues.dlang.org/show_bug.cgi?id=596 --- Comment #15 from bearophile_h...@eml.cc --- See also the work-in-progress specs for pattern matching in C#: https://onedrive.live.com/view.aspx?resid=4558A04E77D0CF5!5396app=Word --
[Issue 596] Support array, arrayliteral and struct in switch and case
https://issues.dlang.org/show_bug.cgi?id=596 --- Comment #14 from bearophile_h...@eml.cc --- Meta in the D newsgroup suggests other names for unapply: opDestructure or opMatch. I think opMatch sounds good and better than unapply for D. --
[Issue 596] Support array, arrayliteral and struct in switch and case
http://d.puremagic.com/issues/show_bug.cgi?id=596 --- Comment #13 from bearophile_h...@eml.cc 2013-03-29 15:51:03 PDT --- It's useful to switch on struct values: import std.bigint; void main() { auto x = BigInt(3); switch (x) { case BigInt(0): break; default: break; } } Other examples of Phobos structs that is useful to switch on are Nullable, Algebraic, etc. Switching on structs is more easy if the struct has no ctor. So it's a POD (despite having some other method). To support the general case of structs that have a constructor such structs need a standard method named like unapply, that is used by the switch itself. This is the solution used by Scala language: http://www.scala-lang.org/node/112 This example is in Scala language: object Twice { def apply(x: Int): Int = x * 2 def unapply(z: Int): Option[Int] = if (z%2 == 0) Some(z/2) else None } object TwiceTest extends Application { val x = Twice(21) x match { case Twice(n) = Console.println(n) } // prints 21 } It's equivalent to the D code: import std.stdio; import std.typecons: Nullable; struct Twice { int static opCall(int x) { return x * 2; } Nullable!int unapply(int z) { if (z % 2 == 0) return typeof(return)(z / 2); else return typeof(return).init; } } void main() { immutable int x = Twice(21); assert(x == 42); switch (x) { case Twice(n): writeln(n); // prints 21 break; default: } } A different example: import std.stdio; import std.typecons: Nullable; struct Foo { int x; this(int x_) { this.x = x_ * 2; } Nullable!int unapply(Foo f1) const { return typeof(return)(f1.x / 2); } } void main() { immutable Foo f2 = Foo(10); assert(f1.x == 20); switch (f2) { case Foo(5): writeln(First case: 5); break; case Foo(n): writeln(n); // Prints: 10 break; default: } } A third example: import std.stdio; struct Even { bool unapply(int x) { return x % 2 == 0; } } void main() { int x = 17; switch (x) { case Even(): writeln(even); break; default: writeln(odd); } } unapply() is allowed to return a bool or a Nullable (including a Nullable of a tuple). For more info: http://lamp.epfl.ch/~emir/written/MatchingObjectsWithPatterns-TR.pdf -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email --- You are receiving this mail because: ---
[Issue 596] Support array, arrayliteral and struct in switch and case
http://d.puremagic.com/issues/show_bug.cgi?id=596 --- Comment #10 from bearophile_h...@eml.cc 2013-03-03 04:24:29 PST --- When final switch supports structs, writing a fizzBuzz (http://imranontech.com/2007/01/24/using-fizzbuzz-to-find-developers-who-grok-coding/ ) gets simpler and safer: import std.stdio, std.typecons; void main() { foreach (immutable i; 1 .. 101) { final switch (tuple(i % 3 == 0, i % 5 == 0)) { case tuple(false, false): writeln(num);break; case tuple(false, true): writeln(Buzz); break; case tuple( true, false): writeln(Fizz); break; case tuple( true, true): writeln(FizzBuzz); break; } } } -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email --- You are receiving this mail because: ---
[Issue 596] Support array, arrayliteral and struct in switch and case
http://d.puremagic.com/issues/show_bug.cgi?id=596 Simen Kjaeraas simen.kja...@gmail.com changed: What|Removed |Added CC||simen.kja...@gmail.com --- Comment #11 from Simen Kjaeraas simen.kja...@gmail.com 2013-03-03 10:16:01 PST --- The problem of your proposed pattern matching is that there is not necessarily a simple correlation between constructor parameters and runtime values. For instance, for this struct declaration: struct Foo { int n; this( int a, int b ) { n = a * b; } } , Foo( 12, void ) just doesn't make any sense. For tuples however, this works: struct DontCare { bool opEquals( T )( T other ) const { return true; } } enum DontCare dontCare = DontCare( ); unittest { import std.typecons : Tuple, tuple; static class A {} auto a = tuple( 12, foo ); assert( a == tuple( 12, dontCare ) ); assert( a == tuple( dontCare, foo ) ); assert( a != tuple( 42, dontCare ) ); assert( a != tuple( dontCare, bar ) ); assert( tuple( 12, dontCare ) == a ); assert( tuple( dontCare, foo ) == a ); assert( tuple( 42, dontCare ) != a ); assert( tuple( dontCare, bar ) != a ); auto aa = new A( ); auto b = tuple( 1.5f, aa ); assert( tuple( 1.5f, dontCare ) == b ); assert( tuple( dontCare, aa ) == b ); assert( tuple( 3.5f, dontCare ) != b ); assert( tuple( dontCare, cast(A)null ) != b ); assert( b == tuple( 1.5f, dontCare ) ); assert( b == tuple( dontCare, aa ) ); assert( b != tuple( 3.5f, dontCare ) ); assert( b != tuple( dontCare, cast(A)null ) ); } This would allow switch statements like this: switch (myTuple) { case tuple( 3, dontCare ): // A break; case tuple( dontCare, foo ): // B break; } -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email --- You are receiving this mail because: ---
[Issue 596] Support array, arrayliteral and struct in switch and case
http://d.puremagic.com/issues/show_bug.cgi?id=596 --- Comment #12 from bearophile_h...@eml.cc 2013-03-03 10:50:27 PST --- (In reply to comment #11) The problem of your proposed pattern matching is that there is not necessarily a simple correlation between constructor parameters and runtime values. For instance, for this struct declaration: struct Foo { int n; this( int a, int b ) { n = a * b; } } , Foo( 12, void ) just doesn't make any sense. For tuples however, this works: Arrays don't have a constructor, so they don't have this problem in a switch. Regarding structs, the problem has some solutions (both are needed): 1) Don't accept structs that have one or more constructors, and special-case std.typecons.Tuple in the compiler so tuples are accepted (the compiler assumes their constructor is just a series of field assignments). 2) If you want to support the general case of structs that have a constructor, then such structs must have a standard method like unapply, that is used by the switch itself. This is the solution used by Scala language, it's shown in the Comment 9: http://d.puremagic.com/issues/show_bug.cgi?id=596#c9 -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email --- You are receiving this mail because: ---
[Issue 596] Support array, arrayliteral and struct in switch and case
http://d.puremagic.com/issues/show_bug.cgi?id=596 --- Comment #9 from bearophile_h...@eml.cc 2013-02-19 16:22:06 PST --- To match classes Scala uses the standard method unapply: http://www.scala-lang.org/node/112 object Twice { def apply(x: Int): Int = x * 2 def unapply(z: Int): Option[Int] = if (z%2 == 0) Some(z/2) else None } object TwiceTest extends Application { val x = Twice(21) x match { case Twice(n) = Console.println(n) } // prints 21 } -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email --- You are receiving this mail because: ---
[Issue 596] Support array, arrayliteral and struct in switch and case
http://d.puremagic.com/issues/show_bug.cgi?id=596 --- Comment #8 from bearophile_h...@eml.cc 2011-09-28 19:13:23 PDT --- Supporting something like this will be very useful (this is done very commonly in functional languages): import std.variant: Algebraic; alias Algebraic!(int, float) A; void main() { A a = 1.5; final switch (a.type()) { case typeid(int): ... case typeid(float): ... } } But if possible I suggest to introduce a compiler optimization specific for this usage, to avoid actually allocating and using TypeInfo class instances. The advantage of using a final switch instead of a sequence of if statements: - The code is more readable, the various cases are shown in a more ordered way; - The final of switch makes sure all types of the Algebraic are taken into account; - The compiler has ways to optimize this code better (sometimes avoiding many runtime tests). -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email --- You are receiving this mail because: ---
[Issue 596] Support array, arrayliteral and struct in switch and case
http://d.puremagic.com/issues/show_bug.cgi?id=596 --- Comment #7 from bearophile_h...@eml.cc 2011-08-15 16:44:27 PDT --- One more useful use is with OOP (this is GUI code): import core.stdc.stdio; class Control {} class Slider : Control {} class Button : Control {} void main() { Control c = new Button; switch (typeof(c)) { case Slider: printf(A); break; case Button: printf(B); break; default: // probably a Control } } That is similar to this (but faster): import core.stdc.stdio; class Control {} class Slider : Control {} class Button : Control {} void main() { Control c = new Button; if (cast(Slider)c) { printf(A); } else if (cast(Button)c) { printf(B); } } -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email --- You are receiving this mail because: ---
[Issue 596] Support array, arrayliteral and struct in switch and case
http://d.puremagic.com/issues/show_bug.cgi?id=596 --- Comment #5 from bearophile_h...@eml.cc 2011-03-21 18:24:53 PDT --- If structs too gets supported by switch, then BigInts too become allowed: import std.bigint; void main() { auto x = BigInt(3); switch (x) { case BigInt(0): break; default: break; } } -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email --- You are receiving this mail because: ---
[Issue 596] Support array, arrayliteral and struct in switch and case
http://d.puremagic.com/issues/show_bug.cgi?id=596 --- Comment #4 from bearophile_h...@eml.cc 2011-01-30 06:37:06 PST --- (In reply to comment #3) struct Foo { int x, y; } void main() { auto f = Foo(1, 2); int f; switch (f) { case Foo(1, _): break; // all structs where x==1, y == don't care default: break; } } The idea of wildcards is very useful, it turns the D switch into something useful to partially match Tuples too. This is a very commonly used operation in functional languages. But probably the _ (underscore) is not right as wildcard, because while it's nice and clear, it's a legal variable name. Possible alternatives are a single , or @ or %: case Foo(1, ): break; case Foo(1, @): break; case Foo(1, %): break; Or maybe just void, that is longer, but adds no new tokens and is more clear than an arbitrary symbol: import std.typecons: Tuple; alias Tuple!(int, x, int, y) Foo; void main() { auto f = Foo(1, 2); switch (f) { case Foo(1, void): break; // any Foo with x==1, don't care y default: break; } } -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email --- You are receiving this mail because: ---
[Issue 596] Support array, arrayliteral and struct in switch and case
http://d.puremagic.com/issues/show_bug.cgi?id=596 --- Comment #3 from bearophile_h...@eml.cc 2011-01-07 05:13:09 PST --- A possible improvement for the switch on structs is to support wildcards in some way: struct Foo { int x, y; } void main() { auto f = Foo(1, 2); int f; switch (f) { case Foo(1, _): break; // all structs where x==1, y == don't care default: break; } } -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email --- You are receiving this mail because: ---
[Issue 596] Support array, arrayliteral and struct in switch and case
http://d.puremagic.com/issues/show_bug.cgi?id=596 Andrei Alexandrescu and...@metalanguage.com changed: What|Removed |Added Status|NEW |ASSIGNED CC||and...@metalanguage.com AssignedTo|nob...@puremagic.com|bugzi...@digitalmars.com -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email --- You are receiving this mail because: ---
[Issue 596] Support array, arrayliteral and struct in switch and case
http://d.puremagic.com/issues/show_bug.cgi?id=596 bearophile_h...@eml.cc changed: What|Removed |Added CC||bearophile_h...@eml.cc --- Comment #2 from bearophile_h...@eml.cc 2010-11-26 12:37:59 PST --- If structs become supported by switch, then an interesting use case is to support Tuples of typecons too. (A possible enhancement is to support class references too (comparing the dynamic type), but similar switches on objects is considered a bad practice in OO code. So maybe it's better to not support class references). -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email --- You are receiving this mail because: ---