30

I'm learning D and have seen a lot of code like this:

ushort x = to!ushort(args[1]);

I assume this casts args[1] to ushort, but what's the difference between this and cast(ushort)?

EDIT: And what other uses does the exclamation mark operator have?

thwd
  • 23,956
  • 8
  • 74
  • 108

3 Answers3

38

In D,

to!ushort(args[1])

is shorthand for the template instantiation

to!(ushort)(args[1])

and is similar to

to<ushort>(args[1])

in languages like C++/Java/C#.

The exclamation point is to note the fact that it's not a regular argument, but a template argument.

The notation does not use angle brackets because those are ridiculously difficult to parse correctly for a compiler (they make the grammar very context-sensitive), which makes it that much more difficult to implement a correct compiler. See here for more info.

The only other use I know about is just the unary 'not' operation (e.g. false == !true)... I can't think of any other uses at the moment.


Regarding the cast:

cast(ushort) is an unchecked cast, so it won't throw an exception if the value is out of range.

to!ushort() is a checked cast, so it throws an exception if the value is out of range.

user541686
  • 205,094
  • 128
  • 528
  • 886
  • 3
    It seems also that to! is more of a lexical cast, for example to!string(f) is valid for floating point f and cast(string)f - not. – Mihails Strasuns Dec 24 '11 at 10:10
  • 5
    I would point out that technically speaking `to!ushort(val)` is not actually a cast. It's a conversion using the function `std.conv.to`. It _is_ checked, but if you start calling it a cast, you risk causing confusion. Casting is only done with the cast operator. – Jonathan M Davis Dec 24 '11 at 19:35
  • @ Михаил Страшун That's because `std.conv.to` does a lot more than check that casts are valid before it does them. It deals with conversions in general. `std.conv.to` is a general conversion function and is extremely flexible. – Jonathan M Davis Dec 24 '11 at 19:38
3

The exclamation mark here is not an operator, it is just a token part of the explicit template instantiation syntax (described in detail here).

std.conv.to (docs) is a function template for converting between arbitrary types. It is implemented entirely in the library and has no special support in the language. It has a broader and different scope compared to the cast operator.

The to template takes two type parameters; a "to" type and a "from" type, in that order. In your example, the template is explicitly instantiated with the single type argument ushort for the "to" parameter, and a second type argument string (assuming args comes from the first parameter to main) is automatically inferred from the regular function argument passed to the function (args[1]) as the "from" parameter.

The resulting function takes a string parameter and returns a ushort parsed from that string, or throws an exception if it failed. The cast operator will not attempt this kind of high-level conversion.

Note that if there is more than one explicit template parameter, or that parameter has more than one token in it (ushort is a single keyword token), you must wrap the template parameter list in parentheses:

ushort result;
result = to!(typeof(result))(args[1]);

In this example, typeof, (, result and ) are four separate tokens and the parentheses are thus required.

To answer your last question, the ! token is also used for the unary not operator, unrelated to template instantiations:

bool yes = true;
bool no = !yes; // 'no' is false
jA_cOp
  • 3,275
  • 19
  • 15
3

You already got two excellent answers by jA_cOp and Merhdad. I just want answer directly to the OP question (what's the difference between this and cast(ushort)?) - The difference is that cast(ushort)args[1] will not work (you cannot cast from a string to an uint just like that), while the to!(type)(param) template knows what to do with the string and how to convert it to the primitive type.

DejanLekic
  • 18,787
  • 4
  • 46
  • 77