[Issue 596] Support array, arrayliteral and struct in switch and case

2019-06-04 Thread d-bugmail--- via Digitalmars-d-bugs
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

2015-06-09 Thread via Digitalmars-d-bugs
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

2014-11-12 Thread via Digitalmars-d-bugs
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

2014-07-09 Thread via Digitalmars-d-bugs
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

2013-03-29 Thread d-bugmail
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

2013-03-03 Thread d-bugmail
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

2013-03-03 Thread d-bugmail
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

2013-03-03 Thread d-bugmail
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

2013-02-19 Thread d-bugmail
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

2011-09-28 Thread d-bugmail
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

2011-08-15 Thread d-bugmail
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

2011-03-21 Thread d-bugmail
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

2011-01-30 Thread d-bugmail
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

2011-01-07 Thread d-bugmail
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

2010-11-26 Thread d-bugmail
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

2010-11-26 Thread d-bugmail
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: ---