Thread overview
Idea: A Better opCast
Apr 01, 2005
pragma
Re: A Better opCast
Apr 01, 2005
Jamboree
Apr 01, 2005
pragma
Apr 01, 2005
Regan Heath
Apr 01, 2005
pragma
Re: A Better opCast
Apr 01, 2005
Ben Hinkle
Apr 01, 2005
pragma
Apr 03, 2005
Stewart Gordon
April 01, 2005
Quoth the manual: "Since functions cannot be overloaded based on return value, there can be only one opCast per struct or class."

Since we only have one opCast to burn, why not change its signature to something more general purpose?

> void* opCast(TypeInfo from);

I came across this idea after I saw how cast() is actually implemented in phobos.  In this case, opCast() could take the place of both _d_interface_cast *and* _d_dynamic_cast as "this" already provides the needed from pointer.

Example:

class Tester{
void* opCast(TypeInfo from){
else if(from = typeid(int)){
int value = 28;
return cast(void*)value; // mimic the example in the docs.
}
return null;
}
}

The above method has a *lot* more power than the current use of opCast().  I"ll
also add that we're already used to working with TypeInfo and typeid() thanks to
_arguments (varargs), so this doesn't clash with what we have already.

I would anticipate that opCast() only be called when a normal dynamic cast or interface cast fails.  This way, the above defintion will interoperate with a class' normal casting behavior.

- EricAnderton at yahoo
April 01, 2005
"pragma" <pragma_member@pathlink.com> wrote in message news:d2i7a1$2ase$1@digitaldaemon.com...
> Quoth the manual: "Since functions cannot be overloaded based on return value, there can be only one opCast per struct or class."
>
> Since we only have one opCast to burn, why not change its signature to something more general purpose?
>
>> void* opCast(TypeInfo from);
>
> I came across this idea after I saw how cast() is actually implemented in phobos.  In this case, opCast() could take the place of both _d_interface_cast *and* _d_dynamic_cast as "this" already provides the needed from pointer.
>
> Example:
>
> class Tester{
> void* opCast(TypeInfo from){
> else if(from = typeid(int)){
> int value = 28;
> return cast(void*)value; // mimic the example in the docs.
> }
> return null;
> }
> }
>
> The above method has a *lot* more power than the current use of opCast().  I"ll
> also add that we're already used to working with TypeInfo and typeid() thanks to
> _arguments (varargs), so this doesn't clash with what we have already.
>
> I would anticipate that opCast() only be called when a normal dynamic cast or interface cast fails.  This way, the above defintion will interoperate with a class' normal casting behavior.

It's elegant, but it'd only result in runtime errors, which would loose a lot of very useful compile-time checking.

D's not Python. :-)



April 01, 2005
On Fri, 1 Apr 2005 01:14:41 +0000 (UTC), pragma <pragma_member@pathlink.com> wrote:
> Quoth the manual: "Since functions cannot be overloaded based on return value,
> there can be only one opCast per struct or class."
>
> Since we only have one opCast to burn, why not change its signature to something
> more general purpose?
>
>> void* opCast(TypeInfo from);
>
> I came across this idea after I saw how cast() is actually implemented in
> phobos.  In this case, opCast() could take the place of both _d_interface_cast
> *and* _d_dynamic_cast as "this" already provides the needed from pointer.
>
> Example:
>
> class Tester{
> void* opCast(TypeInfo from){
> else if(from = typeid(int)){
> int value = 28;
> return cast(void*)value; // mimic the example in the docs.
> }
> return null;
> }
> }
>
> The above method has a *lot* more power than the current use of opCast().  I"ll
> also add that we're already used to working with TypeInfo and typeid() thanks to
> _arguments (varargs), so this doesn't clash with what we have already.
>
> I would anticipate that opCast() only be called when a normal dynamic cast or
> interface cast fails.  This way, the above defintion will interoperate with a
> class' normal casting behavior.

Did you actually mean "void* opCast(TypeInfo from);" or should it be "void* opCast(TypeInfo to);". Your example seems to be casting "to" the type not "from" the type.

Regan
April 01, 2005
> Example:
>
> class Tester{
> void* opCast(TypeInfo from){
> else if(from = typeid(int)){
> int value = 28;
> return cast(void*)value; // mimic the example in the docs.
> }
> return null;
> }
> }

I think the return type will be a problem. The example in the doc illstrates casting to a long by going through an int. If opCast is given the type to cast to how can it know how big the output should be? For example it's not a good idea in your example to cast the int 28 to a pointer. Maybe &value but then it's a reference to a local variable which will be bogus after returning. The generality of passing in the type to cast to is cool. I hope the details can be worked out. It's kindof like dynamic casting but to anything - not just between class types.

> I would anticipate that opCast() only be called when a normal dynamic cast
> or
> interface cast fails.  This way, the above defintion will interoperate
> with a
> class' normal casting behavior.

I don't follow this part. How would opCast interact with normal casting?


April 01, 2005
In article <opsoi75p0x23k2f5@nrage.netwin.co.nz>, Regan Heath says...
>
>Did you actually mean "void* opCast(TypeInfo from);" or should it be "void* opCast(TypeInfo to);". Your example seems to be casting "to" the type not "from" the type.
>

You're right, it's 'to', not 'from'.  That's what I get for not being more thourough before posting.

- EricAnderton at yahoo
April 01, 2005
A correction that was mentioned earlier, the method signature should be:

void* opCast(TypeInfo to);

In article <d2ijpp$2pgb$1@digitaldaemon.com>, Ben Hinkle says...
>
>I think the return type will be a problem. The example in the doc illstrates casting to a long by going through an int. If opCast is given the type to cast to how can it know how big the output should be? For example it's not a good idea in your example to cast the int 28 to a pointer. Maybe &value but then it's a reference to a local variable which will be bogus after returning. The generality of passing in the type to cast to is cool. I hope the details can be worked out. It's kindof like dynamic casting but to anything - not just between class types.


Thanks for thinking that it might be plausable for D.

As for the size, the example above is (for now) a what-if.  I'm not sure how primitives should be returned, but I would imagine that casting any value to it's closest size_t size representation (be it the actual value or a pointer) may be what's called-for.  I can already forsee problems with types like cent.

As you say, I hope these details can be worked out.

>
>> I would anticipate that opCast() only be called when a normal dynamic cast
>> or
>> interface cast fails.  This way, the above defintion will interoperate
>> with a
>> class' normal casting behavior.
>
>I don't follow this part. How would opCast interact with normal casting?
>

Given the following:

A a = new A();
int x = cast(int)a;
B b = cast(B)a; // A and B are not related

The compiler would generate code that does this:

A a = new A();
int x = a.opCast(typeid(int));
B temp = _d_interface_cast(a,typeid(B)); // use a standard cast
b = temp ? temp : a.opCast(typeid(B));  // use the operator on failure


For all I know, the current implementation opCast() already does this.  I thought I'd include this bit as the order of operation between a class' normal casting rules and the opCast override.

However, I'll add that it might actually make more sense to reverse the order of operation so that opCast behaves more like an override instead.

- EricAnderton at yahoo
April 01, 2005
void* opCast(TypeInfo *to);

In article <d2i83d$2bh6$1@digitaldaemon.com>, Jamboree says...
>
>It's elegant, but it'd only result in runtime errors, which would loose a lot of very useful compile-time checking.

I agree that improper use of this kind of casting mechanism could lead to issues. However, this is done with already existing language constructs, so the power to screw things up as badly alrady exists for every other portion of the language.

Also, keep in mind that we already do this with varargs: they're just about as type-unsafe when you get down to it.

>
>D's not Python. :-)
>

Agreed.  But my motivation for this goes outside making types more 'plastic' or 'dynamic' as they are in scripting languages.  Believe me when I say that I want to better enhance D's type system so it can be more *consistent*.  I think this can help.

For example, casts fail when types are used between dlls and their host programs (different TypeInfo trees make vanilla cast() fail).  If an opCast override like this were available, I could do this on every type exported from a dll:

> void* opCast(TypeInfo *to){
>     return classname_cast(this,to); // cast based on name instead of typeid
> }

.. where 'classname_cast' performs the real magic of resolving parallel TypeInfo trees by using classnames instead of TypeInfo references.

I'm sure there's other practical uses for an enhanced opCast() as well.

- EricAnderton at yahoo
April 03, 2005
pragma wrote:
> Quoth the manual: "Since functions cannot be overloaded based on return value,
> there can be only one opCast per struct or class."
> 
> Since we only have one opCast to burn, why not change its signature to something
> more general purpose?
<snip>
> class Tester{
> void* opCast(TypeInfo from){
> else if(from = typeid(int)){
> int value = 28;
> return cast(void*)value; // mimic the example in the docs.
> }
> return null;
> }
> }
<snip>

Problems:

(a) It's rather down and dirty.

(b) What sense does it make to have a pointer to the memory address denoted by the number 28?

(c) I'm not sure how efficient it would be generally.

(d) D has enough features for postponing compile-time errors to the runtime already.

Of the ideas suggested already, my vote would go to

    void opCast(out T value)

Though I've just another idea involving a special syntax for cast functions.  How about this?

    T cast() { ... }

I thought of it as it looks just like an ordinary function definition, the difference being that 'cast' is a keyword.  As such, one cannot call the function directly, but only by using a CastExpression.

You could see it as a special function name that allows return type overloading.  Though really, the 'cast' keyword is a placeholder, rather like 'this' for constructors/destructors.  Of course the functions would have different names internally, using the name mangling convention in some form to indicate the destination type.

Stewart.

-- 
My e-mail is valid but not my primary mailbox.  Please keep replies on on the 'group where everyone may benefit.