December 03, 2003
Berin Loritsch wrote:
> Not necessarily.  As long as there is no ambiguity, the implicit cast should
> continue to work:
> 
> interface Bar {}
> 
> int foo(Bar baz)
> {
>     return 1;
> }
> 
> class SubClass : Bar {}
> 
> // .... in client code later on
> 
> foo( new SubClass() );
> 
> // or
> 
> foo( getInstance() ); // returning SubClass or other impl of Bar

I think there is some kind of misunderstanding.

If getInstance() returns a sub class of Bar, then there will be no cast necessary, because the returned object already is of the correct type.

> What we are talking about is leveraging the strong typing so that you
> can never *upcast*.

Ah. I think I understand what you want. You just want to remove casting altogether, thus only allowing what you call "implicit casts", i.e. casts to a base type?

Wouldn't work. For example, sometimes you just have to pass a sub class thorugh a program component that only knows the base class and cast it back up to the original type afterwards.

Btw, what *I* thought you meant is to use temporary variables to perform a real cast. I.e. allow assigning any type to a local variable when that variable is constructed:

Bar getBar();
void setFoo(Foo foo);

Foo foo=getBar();

but not

setFoo(getBar());

for unrelated types Foo and Bar.

THAT would water down D's type system!

> The only upcast that should ever work is one from the generic object type
> to an Interface.  Once there is a definite type, no more upcasting.

That would just make casting harder, since you'd first have to cast down to Object and then back up to the class you want.

Hauke


December 03, 2003
Hauke Duden wrote:

> Berin Loritsch wrote:
> 
>> What we are talking about is leveraging the strong typing so that you
>> can never *upcast*.
> 
> 
> Ah. I think I understand what you want. You just want to remove casting altogether, thus only allowing what you call "implicit casts", i.e. casts to a base type?
> 
> Wouldn't work. For example, sometimes you just have to pass a sub class thorugh a program component that only knows the base class and cast it back up to the original type afterwards.

Bad code.  Shouldn't do it.  More often than not, upcasting from a base type
other than the generic "object" is a poor substitute for what you really
want.  That's what interfaces are for.  You specify your contracts in the
interface, and pass your object so that the code uses the interface AND NOTHING
ELSE.

> Btw, what *I* thought you meant is to use temporary variables to perform a real cast. I.e. allow assigning any type to a local variable when that variable is constructed:
> 
> Bar getBar();
> void setFoo(Foo foo);
> 
> Foo foo=getBar();
> 
> but not
> 
> setFoo(getBar());
> 
> for unrelated types Foo and Bar.
> 
> THAT would water down D's type system!

Please, no.

>> The only upcast that should ever work is one from the generic object type
>> to an Interface.  Once there is a definite type, no more upcasting.
> 
> 
> That would just make casting harder, since you'd first have to cast down to Object and then back up to the class you want.

That is the point.  Some things like collections *have* to use Object, so at
that time you upcast to the interface you want.  Notice, that I limited the
upcast from object to interfaces?

Granted this would nicely fit the way I work--but not everyone in the world.

December 04, 2003
>     a.b.cast(Foo).c.d.cast(Bar).e.f
> is easier to read than:
>     (cast(Bar)((cast(Foo)(a.b)).c.d)).e.f

> Bar myBar = a.b;
> Foo myFoo = myBar.c.d;
> myFoo.e.f;

An idea, what if we could write

mything = cast(foo)g.cast(bar)h.i.j.cast(baz)k;

Then the top example above, if I've understood it correctly, becomes

a.cast(Foo)b.c.cast(Bar)d.e.f

If we have to do a hairy mix of casts and methods it
would still be legible:

a.cast(I)b.factMethod(cast(J)c).method(cast(K)d,cast(L)e)




December 04, 2003
Berin Loritsch wrote:
>> Wouldn't work. For example, sometimes you just have to pass a sub class thorugh a program component that only knows the base class and cast it back up to the original type afterwards.
> 
> 
> Bad code.  Shouldn't do it.  More often than not, upcasting from a base type
> other than the generic "object" is a poor substitute for what you really
> want. 

That is a pretty sweeping statement you make there. Here's an example against that:

Consider an image manupulation algorithm that takes quite a while. It takes a bunch of objects of type Bitmap and works on them. However, YOUR bitmaps are of the type BitmapWithName, which is derived from Bitmap.

The algorithm calls a progress function regularly, in which you update your GUI to reflect the progress. The current bitmap the algorithm works on is passed to that function, as a Bitmap reference. Since you want to display the name of the current bitmap and you know that all objects you feed the algorithm are your own BitmapWithName objects, you have to cast the object you get up to that class, in order to retrieve its name.

Presto: an upcast from a class other than Object.

Hauke

December 04, 2003
In article <bqjrg3$19kg$1@digitaldaemon.com>, Matthew Wilson wrote:
> "Walter" <walter@digitalmars.com> wrote in message news:bqjfni$nc0$1@digitaldaemon.com...
>>
>> "Dario" <supdar@yahoo.com> wrote in message news:bkvsqs$26e9$1@digitaldaemon.com...
>> > Antti Sykäri:
>> > > I stared that for a moment and thought that you surely made a typo
> there
>> > > and actually meant to write:
>> > > b.cast(B).func();
>> > > Which kind of makes sense.
>> >
>> > That wan't a typo! ;-)
>> > I thought of that because Ant's version is complicated to parse
>> > (function don't get types as parameters).
>> > Anyway I am convinced that Ant's version is more intuitive too.
>> >
>> > I noticed that there are no comments from Walter...
>> > Walter, what do you think? You aren't going to keep the
>> > prefix cast, are you?
>>
>> The postfix cast does look good, but I don't see it has much advantage over the prefix cast.
> 
> Looks too much like a function call to me. What's wrong with cast(B, b) ?

Looks like a function call? ;-)

But seriously, it does!

-Antti

December 04, 2003
"Russ Lewis" <spamhole-2001-07-16@deming-os.org> wrote in message news:bql580$4ki$1@digitaldaemon.com...
> Walter wrote:
> > The postfix cast does look good, but I don't see it has much advantage
over
> > the prefix cast.
>
> I like the idea of postfix cast because it makes long chained
> expressions easier to read.  IMHO, this:
> a.b.cast(Foo).c.d.cast(Bar).e.f
> is easier to read than:
> (cast(Bar)((cast(Foo)(a.b)).c.d)).e.f

Hmmm. There's some mileage in the C++ philosophy of not facilitating the ease-of-expression; maybe casts should be nasty to type?



December 04, 2003
Hauke Duden wrote:
> Berin Loritsch wrote:
> 
>>> Wouldn't work. For example, sometimes you just have to pass a sub class thorugh a program component that only knows the base class and cast it back up to the original type afterwards.
>>
>>
>>
>> Bad code.  Shouldn't do it.  More often than not, upcasting from a base type
>> other than the generic "object" is a poor substitute for what you really
>> want. 
> 
> 
> That is a pretty sweeping statement you make there. Here's an example against that:

;P You noticed?

> 
> Consider an image manupulation algorithm that takes quite a while. It takes a bunch of objects of type Bitmap and works on them. However, YOUR bitmaps are of the type BitmapWithName, which is derived from Bitmap.
> 
> The algorithm calls a progress function regularly, in which you update your GUI to reflect the progress. The current bitmap the algorithm works on is passed to that function, as a Bitmap reference. Since you want to display the name of the current bitmap and you know that all objects you feed the algorithm are your own BitmapWithName objects, you have to cast the object you get up to that class, in order to retrieve its name.
> 
> Presto: an upcast from a class other than Object.

Counter example:

You know that somethimes there will be objects that must be namable, so
you create an interface to represent that concern called "Namable" which
essentially consists of a getName() method.  Your new BitmapWithName object
implements the Bitmap and Namable interfaces.  The Progress function performs
something like this:

char[] name = "";
if ( progressiveObject instanceof Nameable )
{
    Nameable obj = progressiveObject;
    name = obj.getName();
}

At least that is what you do in Java.

If you make your contract directly with an Object, your code is bound to that
object.  If that object is horribly written and is cast aside later on your
code will break in many unexpected ways.  However if you make a contract with
an interface, ANY object that implements that interface can be used.  In fact
your functions become more flexible and reusable because the progress function
no longer expects to deal with Bitmap objects, but anything that can be namable.

December 04, 2003
Berin Loritsch wrote:
>> Presto: an upcast from a class other than Object.
> 
> 
> Counter example:
> 
> You know that somethimes there will be objects that must be namable, so
> you create an interface to represent that concern called "Namable" which
> essentially consists of a getName() method.  Your new BitmapWithName object
> implements the Bitmap and Namable interfaces.

That would work too, but you cannot FORCE programmers to use interfaces for everything. In particular, if you just need a quick prototype (for example, for a demo that needs to be done yesterday) you'd probably want the option to just declare the functionality you need directly in the object class, without having to define additional interfaces.

Also, right now there is a serious limitation to D's interfaces that pretty much prevents them from being used in that way. I always wanted to write an longer post about this issue, but never got around to it.

The main problem is that if a class implements an interface A and a derived class wants to implement a sub-interface "B" of A, then you have to re-implement all the functions of A again (probably with stubs that call the base class). This is a serious issue if you build an interface hierarchy and want to reuse an existing implementation of a base-interface as a basis for an implementation of a more specific interface (which you often want!). You end up writing dozens of stub-methods that do nothing except calling the base class implementation, for each and every class and every interface it implements.

I'll try to write the post on that topic tonight, with a better explanation of what I mean. This issue is actually pretty important to me, even critical for my decision of whether I'll ever switch to D. So I want to make sure that my point is understandable.

Hauke
December 04, 2003
In article <bqmiig$2901$1@digitaldaemon.com>, Matthew Wilson says...
>
>
>"Russ Lewis" <spamhole-2001-07-16@deming-os.org> wrote in message news:bql580$4ki$1@digitaldaemon.com...
>> Walter wrote:
>> > The postfix cast does look good, but I don't see it has much advantage
>over
>> > the prefix cast.
>>
>> I like the idea of postfix cast because it makes long chained
>> expressions easier to read.  IMHO, this:
>> a.b.cast(Foo).c.d.cast(Bar).e.f
>> is easier to read than:
>> (cast(Bar)((cast(Foo)(a.b)).c.d)).e.f
>
>Hmmm. There's some mileage in the C++ philosophy of not facilitating the ease-of-expression; maybe casts should be nasty to type?

You might be right but anyway you cut it
shoud be easy to read,
that's the only advantage we a seeking with the postfix idea.

Ant


December 07, 2003
from:  http://www.digitalmars.com/drn-bin/wwwnews?D/19990

I've remembered that I thought about cast expression this April
(but independently of D,)
and have found the memo which was written then.


I introduced two types of *postfix* cast in the memo.
One is `down_cast' for down cast and another is `cast' for the other cast
(exactly I introduced also `up_cast' for the case of multiple inheritance.)

e.g.)
A a = new A;
B b = a.cast(B);
C c = a.down_cast(D);

The memo also says as follows:

Casts are similar to constructors,
but casts are opposite processes to constructors.
Because "A a = new A; B b = a.cast(B);" makes
B's instance from A's instance though the `cast' is A's member function.
It gives the same result as new B(a) (if B(A) is defined,)
however, the cast can be implemented even if B knows *nothing* about A.
This is a very important aspect of casts,
and supports that casts must be subject to the casted classes.

Casts are treated as member functions, but the syntax is special.
Because return value types are given from the arguments.
It's a unique property of casts.
Many cast functions seem to have no arguments (the same arguments),
but they can be overloaded.

`implicit' keyword allows implicit cast if not ambiguous. Overloaded casts should be explicit by default.

e.g.)
struct Point {
public int x, y;
public Size cast() {
return new Size(x, y);
}
public implicit LongPoint cast() {
return new LongPoint(x, y);
}
}
Point pt;
Size siz = pt.cast(size);
LongPoint lpt = pt;

Cast methods can have some additional arguments if necessary.

Down casts must be treated with especial care,
must not be overloaded, and make no instances,
so they should be distinguished from normal casts and
should be done with special keyword.


Though some specs may be bizarre,
I would appreciate hearing advices for it.

Robert (Japanese)
1 2 3 4 5
Next ›   Last »