www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Pattern matching via switch?

reply 12345swordy <alexanderheistermann gmail.com> writes:
I.E.

switch (object)
     case Type1 t1:
     case Type2 t2:
     case Type3 t3:
Mar 14 2020
next sibling parent reply aliak <something something.com> writes:
On Saturday, 14 March 2020 at 19:04:28 UTC, 12345swordy wrote:
 I.E.

 switch (object)
     case Type1 t1:
     case Type2 t2:
     case Type3 t3:
You can use the sumtype package (https://code.dlang.org/packages/sumtype): alias T = SumType!(Type1, Type2, Type3); T(object).match!( (Type1 t1) => "t1", (Type2 t2) => "t2", (Type3 t3) => "t3", ); Or you can make a quick template like: template switch_(funs...) { auto switch_(T)(auto ref T t) { static foreach (fun; funs) { static if (is(typeof(fun(T.init)))) { return fun(t); } } } } struct A {} struct B {} struct C {} void main() { auto a = C(); a.switch_!( (A _) => "a", (B _) => "b", (C _) => "c", ).writeln; } The template above is a quick fix and will have some holes though. Off the top of my head if more than one lambda "fits" there'll be problems.
Mar 14 2020
parent 12345swordy <alexanderheistermann gmail.com> writes:
On Saturday, 14 March 2020 at 20:52:30 UTC, aliak wrote:
 On Saturday, 14 March 2020 at 19:04:28 UTC, 12345swordy wrote:
     [...]
You can use the sumtype package (https://code.dlang.org/packages/sumtype): [...]
That simply to much verbiage.
Mar 14 2020
prev sibling next sibling parent Luhrel <lucien.perregaux gmail.com> writes:
On Saturday, 14 March 2020 at 19:04:28 UTC, 12345swordy wrote:
 I.E.

 switch (object)
     case Type1 t1:
     case Type2 t2:
     case Type3 t3:
As far as I know, there's no way to do that in a switch. However, you can do something like this: --- void main() { auto i = new Type1(); foo(i); } void foo(T)(T type) { static if (is(T == Type1)) { // ... } else static if (is(T == Type2)) { // ... } // ... } --- Hope this helps
Mar 14 2020
prev sibling next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 3/14/20 3:04 PM, 12345swordy wrote:
 I.E.
 
 switch (object)
      case Type1 t1:
      case Type2 t2:
      case Type3 t3:
 
Is this a class object and you are trying to determine at runtime which derived type it is and perform an action based on that? Or are you trying to switch on the type of a concrete item? It should technically be possible to use the fully qualified name to switch on, but I don't think typeid(Type1).name is usable as a switch label. -Steve
Mar 15 2020
parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Sunday, 15 March 2020 at 17:55:59 UTC, Steven Schveighoffer 
wrote:
 On 3/14/20 3:04 PM, 12345swordy wrote:
 I.E.
 
 switch (object)
      case Type1 t1:
      case Type2 t2:
      case Type3 t3:
 
Is this a class object and you are trying to determine at runtime which derived type it is and perform an action based on that? Or are you trying to switch on the type of a concrete item? It should technically be possible to use the fully qualified name to switch on, but I don't think typeid(Type1).name is usable as a switch label. -Steve
https://docs.microsoft.com/en-us/dotnet/csharp/pattern-matching object is the top type in that language. https://en.wikipedia.org/wiki/Top_type
Mar 15 2020
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 3/15/20 2:22 PM, 12345swordy wrote:
 On Sunday, 15 March 2020 at 17:55:59 UTC, Steven Schveighoffer wrote:
 On 3/14/20 3:04 PM, 12345swordy wrote:
 I.E.

 switch (object)
      case Type1 t1:
      case Type2 t2:
      case Type3 t3:
Is this a class object and you are trying to determine at runtime which derived type it is and perform an action based on that? Or are you trying to switch on the type of a concrete item? It should technically be possible to use the fully qualified name to switch on, but I don't think typeid(Type1).name is usable as a switch label.
https://docs.microsoft.com/en-us/dotnet/csharp/pattern-matching object is the top type in that language. https://en.wikipedia.org/wiki/Top_type
D doesn't support this natively. The closest you can get is something akin to what aliak wrote (you would need to write something, not sure if Phobos or some package has implemented the feature), or use cascaded if statements: if(auto t1 = cast(Type1)object) // use t1 as Type1 else if(auto t2 = cast(Type2)object) // use t2 as Type2 ... Taking care of course to look for most derived types first. a switch based on static or runtime type would be really cool for D to support. -Steve
Mar 15 2020
parent reply Paolo Invernizzi <paolo.invernizzi gmail.com> writes:
On Sunday, 15 March 2020 at 18:52:01 UTC, Steven Schveighoffer 
wrote:

 D doesn't support this natively. The closest you can get is 
 something akin to what aliak wrote (you would need to write 
 something, not sure if Phobos or some package has implemented 
 the feature), or use cascaded if statements:
I've just given a fast look at the thread, so maybe I'm wrong, but this [1] should be ok for pattern matching using plain and simple Phobos ... [1] https://dlang.org/phobos/std_variant.html#.visit
Mar 17 2020
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 3/17/20 4:18 AM, Paolo Invernizzi wrote:
 On Sunday, 15 March 2020 at 18:52:01 UTC, Steven Schveighoffer wrote:
 
 D doesn't support this natively. The closest you can get is something 
 akin to what aliak wrote (you would need to write something, not sure 
 if Phobos or some package has implemented the feature), or use 
 cascaded if statements:
I've just given a fast look at the thread, so maybe I'm wrong, but this [1] should be ok for pattern matching using plain and simple Phobos ... [1] https://dlang.org/phobos/std_variant.html#.visit
I think he's looking for object pattern matching. i.e. you give it an Object, and it runs a block of code based on the derived type. -Steve
Mar 17 2020
parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 18/03/2020 12:59 AM, Steven Schveighoffer wrote:
 I think he's looking for object pattern matching. i.e. you give it an 
 Object, and it runs a block of code based on the derived type.
In case this syntax is unknown: if (MyObject1 myObject = cast(MyObject1)obj) { ... } else if (MyObject2 myObject = cast(MyObject2)obj) { ... } else { ... }
Mar 17 2020
parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 3/17/20 8:04 AM, rikki cattermole wrote:
 On 18/03/2020 12:59 AM, Steven Schveighoffer wrote:
 I think he's looking for object pattern matching. i.e. you give it an 
 Object, and it runs a block of code based on the derived type.
In case this syntax is unknown: if (MyObject1 myObject = cast(MyObject1)obj) {     ... } else if (MyObject2 myObject = cast(MyObject2)obj) {     ... } else {     ... }
Yes, look a few posts up, that was my recommendation. I don't think there's a "pleasant" way to do this in D. You can do it with delegates, but that's a bit uglier than a switch statement, and has been rejected by the OP. However, I don't think the syntax requested is going to be added to D, as it's an odd syntax: case SomeType inst: // inst now defined as SomeType So that's probably the best bet. -Steve
Mar 17 2020
prev sibling parent DanielG <simpletangent gmail.com> writes:
I've been playing around with this via inheritance lately (I'm 
aware of the sumtype package but specifically wanted to use 
objects instead of structs), had some good results.

It involves a bit of boilerplate though. I'm essentially using 
the visitor pattern + an anonymous class implementing a matcher 
interface:

https://gist.github.com/dewf/dadc0f2775b40b65a3ebf7458d3c2c79

I would love to use templated return values from the match() 
method, though. Does anybody know how to do that without the 
compiler complaining ("'final' functions cannot be 'abstract'") ?

Specifically, is there any way to make:

    abstract void match(Matcher m);

Become:

    abstract T match(T)(Matcher!T m);

?
Mar 16 2020