www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Type deduction using switch case

reply "Xinok" <xinok live.com> writes:
While reading "The Right Approach to Exceptions", it gave me this 
idea. The user would declare a list of variables of different 
types as case statements, and the variable with matches the type 
of the switch expression is used.

I don't know how the syntax should look, this is merely an 
example:

void foo(T)(T arg){
	switch(arg){
		case int i:
			writeln("Type is int ", i); break;
		case float f:
			writeln("Type is float ", f); break;
		case string s:
			writeln("Type is string ", s); break;
		default:
			writeln("Type is unknown"); break;
	}
}

While static if would be more practical for templates, my idea 
could be extended to dynamic upcasting of classes as well, which 
could be applied to exception handling:

try{ ... }
catch(Throwable err) switch(err){
	case IOError a:
		break;
	case OutOfMemoryError b:
		break;
	default:
		throw err;
}
Feb 18 2012
next sibling parent reply "Robert Jacques" <sandford jhu.edu> writes:
On Sat, 18 Feb 2012 18:33:01 -0600, Xinok <xinok live.com> wrote:

 While reading "The Right Approach to Exceptions", it gave me this
 idea. The user would declare a list of variables of different
 types as case statements, and the variable with matches the type
 of the switch expression is used.

 I don't know how the syntax should look, this is merely an
 example:

 void foo(T)(T arg){
 	switch(arg){
 		case int i:
 			writeln("Type is int ", i); break;
 		case float f:
 			writeln("Type is float ", f); break;
 		case string s:
 			writeln("Type is string ", s); break;
 		default:
 			writeln("Type is unknown"); break;
 	}
 }
The above should be switch (T) not switch(arg) for the example to be correct.
 While static if would be more practical for templates, my idea
 could be extended to dynamic upcasting of classes as well, which
 could be applied to exception handling:

 try{ ... }
 catch(Throwable err) switch(err){
 	case IOError a:
 		break;
 	case OutOfMemoryError b:
 		break;
 	default:
 		throw err;
 }
You can do this today using a string switch: switch(err.classinfo.name) { ... }
Feb 18 2012
parent reply "Xinok" <xinok live.com> writes:
On Sunday, 19 February 2012 at 00:49:56 UTC, Robert Jacques wrote:
 On Sat, 18 Feb 2012 18:33:01 -0600, Xinok <xinok live.com> 
 wrote:

 While reading "The Right Approach to Exceptions", it gave me 
 this
 idea. The user would declare a list of variables of different
 types as case statements, and the variable with matches the 
 type
 of the switch expression is used.

 I don't know how the syntax should look, this is merely an
 example:

 void foo(T)(T arg){
 	switch(arg){
 		case int i:
 			writeln("Type is int ", i); break;
 		case float f:
 			writeln("Type is float ", f); break;
 		case string s:
 			writeln("Type is string ", s); break;
 		default:
 			writeln("Type is unknown"); break;
 	}
 }
The above should be switch (T) not switch(arg) for the example to be correct.
Notice how it's "int i" and not just "int". Also notice how each writeln statement also prints the variable. Each case statement declares a variable, so it matches the type of the expression against the type of the variable, and stores the switch expression in that variable.
Feb 18 2012
parent reply "Robert Jacques" <sandford jhu.edu> writes:
On Sat, 18 Feb 2012 20:03:51 -0600, Xinok <xinok live.com> wrote:

 On Sunday, 19 February 2012 at 00:49:56 UTC, Robert Jacques wrote:
 On Sat, 18 Feb 2012 18:33:01 -0600, Xinok <xinok live.com>
 wrote:

 While reading "The Right Approach to Exceptions", it gave me
 this
 idea. The user would declare a list of variables of different
 types as case statements, and the variable with matches the
 type
 of the switch expression is used.

 I don't know how the syntax should look, this is merely an
 example:

 void foo(T)(T arg){
 	switch(arg){
 		case int i:
 			writeln("Type is int ", i); break;
 		case float f:
 			writeln("Type is float ", f); break;
 		case string s:
 			writeln("Type is string ", s); break;
 		default:
 			writeln("Type is unknown"); break;
 	}
 }
The above should be switch (T) not switch(arg) for the example to be correct.
Notice how it's "int i" and not just "int". Also notice how each writeln statement also prints the variable. Each case statement declares a variable, so it matches the type of the expression against the type of the variable, and stores the switch expression in that variable.
And why not simply do: void foo(T)(T arg){ switch(T){ case int: writeln("Type is int ", arg); break; case float: writeln("Type is float ", arg); break; case string: writeln("Type is string ", arg); break; default: writeln("Type is unknown"); break; } }
Feb 18 2012
parent "Xinok" <xinok live.com> writes:
On Sunday, 19 February 2012 at 06:28:37 UTC, Robert Jacques wrote:
 On Sat, 18 Feb 2012 20:03:51 -0600, Xinok <xinok live.com> 
 wrote:
 Notice how it's "int i" and not just "int". Also notice how 
 each
 writeln statement also prints the variable. Each case statement
 declares a variable, so it matches the type of the expression
 against the type of the variable, and stores the switch
 expression in that variable.
And why not simply do: void foo(T)(T arg){ switch(T){ case int: writeln("Type is int ", arg); break; case float: writeln("Type is float ", arg); break; case string: writeln("Type is string ", arg); break; default: writeln("Type is unknown"); break; } }
Because all of the code gets compiled in, so if one statement uses the type incorrectly, it won't compile. It also doesn't allow for dynamic upcasting of classes as in my second example.
Feb 19 2012
prev sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Xinok" <xinok live.com> wrote in message 
news:yeuigezlevjbhgufwrti forum.dlang.org...
 While reading "The Right Approach to Exceptions", it gave me this idea. 
 The user would declare a list of variables of different types as case 
 statements, and the variable with matches the type of the switch 
 expression is used.

 I don't know how the syntax should look, this is merely an example:

 void foo(T)(T arg){
 switch(arg){
 case int i:
 writeln("Type is int ", i); break;
 case float f:
 writeln("Type is float ", f); break;
 case string s:
 writeln("Type is string ", s); break;
 default:
 writeln("Type is unknown"); break;    }
 }

 While static if would be more practical for templates, my idea could be 
 extended to dynamic upcasting of classes as well, which could be applied 
 to exception handling:

 try{ ... }
 catch(Throwable err) switch(err){
 case IOError a:
 break;
 case OutOfMemoryError b:
 break;
 default:
 throw err;
 }
Yea, pattern matching, basically. Great as D is, pattern matching is one thing where Nemerle blows D out of the water: http://nemerle.org/Grok_Variants_and_matching With exceptions in particular, I've often felt that we need some sort of templated catch: try {...} catch(TypeTuple!(ExceptionA, ExceptionB) e) { // Common implementation, but NO need // for that re-throwing abomination you'd // inevitably need if you just caught // a common base type. }
Feb 18 2012
parent David <d dav1d.de> writes:
Am 19.02.2012 02:47, schrieb Nick Sabalausky:
 With exceptions in particular, I've often felt that we need some sort of
 templated catch:

 try {...}
 catch(TypeTuple!(ExceptionA, ExceptionB) e)
 {
      // Common implementation, but NO need
      // for that re-throwing abomination you'd
      // inevitably need if you just caught
      // a common base type.
 }
+1 best would be with built-in Tuples, but I guess built-in tuples are just a dream …
Feb 19 2012