February 20, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=596



--- Comment #9 from bearophile_hugs@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: -------
March 03, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=596



--- Comment #10 from bearophile_hugs@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: -------
March 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


--- Comment #11 from Simen Kjaeraas <simen.kjaras@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: -------
March 03, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=596



--- Comment #12 from bearophile_hugs@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: -------
March 29, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=596



--- Comment #13 from bearophile_hugs@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: -------
1 2
Next ›   Last »