kenji hara:

http://wiki.dlang.org/DIP32

Regarding case values:

switch (tup) {
    case {1, 2}:
    case {$, 2}:
    case {1, x}:    // capture tup[1] into 'x' when tup[0] == 1
    default:        // same as {...}
}


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

Bye,
bearophile

Reply via email to