digitalmars.D.bugs - [Issue 596] New: Support array, arrayliteral and struct in switch and case
- d-bugmail puremagic.com (35/35) Nov 25 2006 http://d.puremagic.com/issues/show_bug.cgi?id=596
- Thomas Kuehne (17/26) Nov 25 2006 -----BEGIN PGP SIGNED MESSAGE-----
- d-bugmail puremagic.com (10/10) Nov 26 2010 http://d.puremagic.com/issues/show_bug.cgi?id=596
- d-bugmail puremagic.com (14/14) Nov 26 2010 http://d.puremagic.com/issues/show_bug.cgi?id=596
- d-bugmail puremagic.com (16/16) Jan 07 2011 http://d.puremagic.com/issues/show_bug.cgi?id=596
- d-bugmail puremagic.com (25/34) Jan 30 2011 http://d.puremagic.com/issues/show_bug.cgi?id=596
- d-bugmail puremagic.com (14/14) Mar 21 2011 http://d.puremagic.com/issues/show_bug.cgi?id=596
- d-bugmail puremagic.com (6/6) Jul 23 2011 http://d.puremagic.com/issues/show_bug.cgi?id=596
- d-bugmail puremagic.com (28/28) Aug 15 2011 http://d.puremagic.com/issues/show_bug.cgi?id=596
- d-bugmail puremagic.com (24/24) Sep 28 2011 http://d.puremagic.com/issues/show_bug.cgi?id=596
- d-bugmail puremagic.com (15/15) Feb 19 2013 http://d.puremagic.com/issues/show_bug.cgi?id=596
- d-bugmail puremagic.com (19/19) Mar 03 2013 http://d.puremagic.com/issues/show_bug.cgi?id=596
- d-bugmail puremagic.com (55/55) Mar 03 2013 http://d.puremagic.com/issues/show_bug.cgi?id=596
- d-bugmail puremagic.com (15/27) Mar 03 2013 http://d.puremagic.com/issues/show_bug.cgi?id=596
- d-bugmail puremagic.com (101/101) Mar 29 2013 http://d.puremagic.com/issues/show_bug.cgi?id=596
http://d.puremagic.com/issues/show_bug.cgi?id=596 Summary: Support array, arrayliteral and struct in switch and case Product: D Version: unspecified Platform: All OS/Version: All Status: NEW Severity: enhancement Priority: P2 Component: DMD AssignedTo: bugzilla digitalmars.com ReportedBy: lovesyao hotmail.com struct Test{ int x; int y; int z; } void main(){ Test* t = new Test; const static Test c1 = {0,0,0}; switch(*t){ case c1://struct break; default: assert(0); } ubyte[] t2 = [0,1,2]; switch(t2){ case [0,1,2]://arrayliteral break; default: } } --
Nov 25 2006
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 d-bugmail puremagic.com schrieb am 2006-11-25:http://d.puremagic.com/issues/show_bug.cgi?id=596void main(){<snip>ubyte[] t2 = [0,1,2]; switch(t2){ case [0,1,2]://arrayliteral break; default: } }Added to DStress as http://dstress.kuehne.cn/run/c/case_05_A.d http://dstress.kuehne.cn/run/c/case_05_B.d http://dstress.kuehne.cn/run/c/case_05_C.d http://dstress.kuehne.cn/run/s/switch_23_A.d http://dstress.kuehne.cn/run/s/switch_23_B.d http://dstress.kuehne.cn/run/s/switch_23_C.d Thomas -----BEGIN PGP SIGNATURE----- iD8DBQFFaIn9LK5blCcjpWoRAmSzAKCoAbyM7GpWeT91ns333aGZOpS/pQCffTPD kFNVqQQA11CBcTe8BRZfUS4= =XNA6 -----END PGP SIGNATURE-----
Nov 25 2006
http://d.puremagic.com/issues/show_bug.cgi?id=596 Andrei Alexandrescu <andrei metalanguage.com> changed: What |Removed |Added ---------------------------------------------------------------------------- Status|NEW |ASSIGNED CC| |andrei metalanguage.com AssignedTo|nobody puremagic.com |bugzilla digitalmars.com -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Nov 26 2010
http://d.puremagic.com/issues/show_bug.cgi?id=596 bearophile_hugs eml.cc changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |bearophile_hugs eml.cc 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: -------
Nov 26 2010
http://d.puremagic.com/issues/show_bug.cgi?id=596 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: -------
Jan 07 2011
http://d.puremagic.com/issues/show_bug.cgi?id=596struct 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: -------
Jan 30 2011
http://d.puremagic.com/issues/show_bug.cgi?id=596 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: -------
Mar 21 2011
http://d.puremagic.com/issues/show_bug.cgi?id=596 Regarding tuple unpacking see also issue 6365 -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Jul 23 2011
http://d.puremagic.com/issues/show_bug.cgi?id=596 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: -------
Aug 15 2011
http://d.puremagic.com/issues/show_bug.cgi?id=596 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: -------
Sep 28 2011
http://d.puremagic.com/issues/show_bug.cgi?id=596 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: -------
Feb 19 2013
http://d.puremagic.com/issues/show_bug.cgi?id=596 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: -------
Mar 03 2013
http://d.puremagic.com/issues/show_bug.cgi?id=596 Simen Kjaeraas <simen.kjaras gmail.com> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |simen.kjaras gmail.com 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: -------
Mar 03 2013
http://d.puremagic.com/issues/show_bug.cgi?id=596The 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: -------
Mar 03 2013
http://d.puremagic.com/issues/show_bug.cgi?id=596 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: -------
Mar 29 2013