March 04, 2003 Re: DMD 0.58 release | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel Yokomiso | "Daniel Yokomiso" <daniel_yokomiso@yahoo.com.br> wrote in message news:b42qvl$fft$1@digitaldaemon.com... > Hmmm, so it'll return 1. This return 2, I suppose: > B b = new B(); > I i = cast(I) b.c; > i.foo(); Yes. > Will this code be valid? > A a = new B(); > a.c = new C(); No. But I don't know how to detect such cases. A big hole. > Or you'll add rules disallowing such classes (i.e. B) to covariantly > redefine some of its attributes types? BTW the quick cheat sheet of variance > is: "in" parameters must be contravariant, "out" and return type must be covariant and inout must be invariant. I never figured out what contravariant is <g>. > The same rules could be applied to > D's type system, and everything would be type-safe. Or we could follow the > Eiffel road and allow CAT calls (i.e. type mismatches due to type anchors, > similar to virtual types). |
March 04, 2003 Re: DMD 0.58 release | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter | In article <b42l2l$beu$1@digitaldaemon.com>, Walter says... > >What I was thinking is to allow: > >class C { } >class D : C { } > >class A >{ > C c; >} > >class B : A >{ > D c; >} > >where A.c shares its storage with B.c, instead of B.c creating a new, distinct member. It will work just like virtual functions (but no vtable is required). With my reading of virtual types, this mechanism looks like it should cover the territory. What do you think? > Here's one problem: (reusing C and D from above) class A { C c; this () { c = new C(...); } } class B : A { D c; this () { super(); } // oops, now my c will refer to a C rather than a D } Eiffel solves this by not requiring you to name the type to construct it -- think "c = new();" rather than "c = new C();". That would seem to require virtual constructors, so you wouldn't even define the constructor in B. Since every other type of method in a class is virtual, there should be ways of designing for this feature. Dan |
March 04, 2003 Re: DMD 0.58 release | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dan Liebgold | "Dan Liebgold" <Dan_member@pathlink.com> wrote in message news:b42u22$ho6$1@digitaldaemon.com... > In article <b42l2l$beu$1@digitaldaemon.com>, Walter says... > > > >What I was thinking is to allow: > > > >class C { } > >class D : C { } > > > >class A > >{ > > C c; > >} > > > >class B : A > >{ > > D c; > >} > > > >where A.c shares its storage with B.c, instead of B.c creating a new, distinct member. It will work just like virtual functions (but no vtable is > >required). With my reading of virtual types, this mechanism looks like it should cover the territory. What do you think? > > > > Here's one problem: (reusing C and D from above) > > class A > { > C c; > this () { c = new C(...); } > } > > class B : A > { > D c; > this () { super(); } // oops, now my c will refer to a C rather than a D > } Yeah, Daniel pointed out an equivalent hole. > Eiffel solves this by not requiring you to name the type to construct it -- > think "c = new();" rather than "c = new C();". That would seem to require > virtual constructors, so you wouldn't even define the constructor in B. > > Since every other type of method in a class is virtual, there should be ways of > designing for this feature. I think the only way to make it work would be to do a runtime check. That also leads to having to set off the declaration of c with some distinct syntax: virtual C c; but I don't like that because it is inconsistent with virtual functions not needing a keyword. I could say it is virtual unless declared final, but that will be too ugly methinks. |
March 04, 2003 Re: typename for forward declarations | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sean L. Palmer | "Sean L. Palmer" <seanpalmer@directvinternet.com> wrote in message news:b42s8h$g8r$1@digitaldaemon.com... > Can we have support for "typename" as in C++? It doesn't have to have the same keyword. > > It's mainly for templates, to indicate to the compiler that something is a type not a value, and for when you don't know whether something is a class, > basic type, enum, or whatever. But that's already syntactically distinguishable: template<T> // T is a type template<U V> // V is a value of type U > I would specifically like for it not to require being in a template, thus we > could use it for any kind of forward declaration where the exact type isn't > needed. > > Unless D doesn't ever need a forward declaration? I suspect that it still would require them in certain cases.. I think D has it covered, but if you have a case in mind, please post it. |
March 04, 2003 Re: DMD 0.58 release | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter | "Walter" <walter@digitalmars.com> escreveu na mensagem news:b42t3p$h4f$1@digitaldaemon.com... > > "Daniel Yokomiso" <daniel_yokomiso@yahoo.com.br> wrote in message news:b42qvl$fft$1@digitaldaemon.com... > > Hmmm, so it'll return 1. This return 2, I suppose: > > B b = new B(); > > I i = cast(I) b.c; > > i.foo(); > > Yes. > > > Will this code be valid? > > A a = new B(); > > a.c = new C(); > > No. But I don't know how to detect such cases. A big hole. It's only possible with global world analysis. Eiffel has such holes, and they are trying to close them now, at least some, in the ECMA standard. I vote against such feature in D. It'll be very easy to produce correct code for it if there's no restriction. OTOH you can just disallow subclass covariance of attributes if in the superclass the attribute is either externally writable (semantics should change) or assigned inside a final method. All methods allowing assignment of such field should then be overriden by the subclass, or a compiler error should be raised. Also issues regarding interface inherited by the superclass and the subclass (leading to two implementations) should be reviewed. interface J { void setC(C c); C getC(); } class E : J { C c; void setC(C newC) { this.c = newC; } C getC() { return this.c; } } class F : E, J { D c; void setC(C newC) { this.c = cast(D) newC; } D getC() { return this.c; } } E e = new F(); J j = cast(J) e; j.setC(new C()); // safety hole here j = cast(J) new F(); j.setC(new C()); // everything fine here Of course if we changed "F.setC(C)" (interface implementation) to "F.setC(D)" (overloading) things could get weirder. BTW I think the interface semantics are officially counter-intuitive right now. Shouldn't this be reviewed? > > Or you'll add rules disallowing such classes (i.e. B) to covariantly > > redefine some of its attributes types? BTW the quick cheat sheet of > variance > > is: "in" parameters must be contravariant, "out" and return type must be covariant and inout must be invariant. > > I never figured out what contravariant is <g>. Here is a good and short link on that: http://sern.ucalgary.ca/courses/SENG/609.03/W98/Abadi/AbadiCh2.html#2.6 > > The same rules could be applied to > > D's type system, and everything would be type-safe. Or we could follow the > > Eiffel road and allow CAT calls (i.e. type mismatches due to type anchors, > > similar to virtual types). --- Outgoing mail is certified Virus Free. Checked by AVG anti-virus system (http://www.grisoft.com). Version: 6.0.459 / Virus Database: 258 - Release Date: 25/2/2003 |
March 04, 2003 Re: DMD 0.58 release | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dan Liebgold | Dan Liebgold wrote:
> In article <b42l2l$beu$1@digitaldaemon.com>, Walter says...
>
>>What I was thinking is to allow:
>>
>>class C { }
>>class D : C { }
>>
>>class A
>>{
>> C c;
>>}
>>
>>class B : A
>>{
>> D c;
>>}
>>
>>where A.c shares its storage with B.c, instead of B.c creating a new,
>>distinct member. It will work just like virtual functions (but no vtable is
>>required). With my reading of virtual types, this mechanism looks like it
>>should cover the territory. What do you think?
>>
>
>
> Here's one problem: (reusing C and D from above)
>
> class A
> {
> C c;
> this () { c = new C(...); }
> }
>
> class B : A
> {
> D c;
> this () { super(); } // oops, now my c will refer to a C rather than a D
> }
>
> Eiffel solves this by not requiring you to name the type to construct it --
> think "c = new();" rather than "c = new C();". That would seem to require
> virtual constructors, so you wouldn't even define the constructor in B.
It would require a virtual constructor and an item in the vtable. But I think it's inevitable - either this energy will come from here, or it will come from constructor methods that have to be overloaded in each subclass.
The thing is, that this seriously violates the spirit of OO. "A" is no longer a gray box to "B", nor can it be, because large classes will balk at the implicit casting involved when you don't use a covariant overload for all methods that refer to class "C", or worse they won't and we'll have type violations:
class A
{
C c;
/* But the C object might not be a D! */
void setC(C value) { c = value; }
}
So it's semantically more complex than Sweeney's Frameworks, with pitfalls, while providing the exact same thing. The only benefit I'm getting from this is that you don't need to pack everything into one master class, which is a serious problem in itself.
|
March 04, 2003 Re: DMD 0.58 release | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel Yokomiso | "Daniel Yokomiso" <daniel_yokomiso@yahoo.com.br> wrote in message news:b432o0$krg$1@digitaldaemon.com... > It's only possible with global world analysis. Eiffel has such holes, > and they are trying to close them now, at least some, in the ECMA standard. > I vote against such feature in D. It'll be very easy to produce correct code > for it if there's no restriction. Hmm, you mean you are against the virtual type feature because you think it will be too easy to produce incorrect code? |
March 05, 2003 Re: DMD 0.58 release | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter |
> > why not ;
> >
> > class A( T : C ) // must define the base class
> > {
> > T c;
> > }
> >
> > class B : A(D)
> > {
> > }
> >
> > I think the syntax is O.K.
>
> It leads to similar ambiguity problems that C++ suffers from with A<D>
>
how ? with A<D it might be an expression
you already have to deal with
type [type] which can look like an array lookup not a type and type(type)
would only appear in the same places and again looks like it might be a func
call
in the class declare is
class <name>['(' <lwt> ')' ] [':' <super> [ '(' <type> [',' <type>]* ')' ]]
'{' <classdef> '}'
rather than
class <name> [':' <super>] '{' <classdef> '}'
I don't see an ambiguity there.
also the problem of
A a = new B();
a.c = new D();
does not exists
you would have to write
A(D) a = new B();
allowing an A without defining its specialisation as a param
void func ( A a ) { /* consider a as a read only ref to an A(C) */ }
with c++ an array or banana is not an array of fruit. in D you can't have an
array of obj (only obj ref like C#/Java)
an array of references to banana however is a readonly array of fruit
(Java allows an array of banana's to be passed as an array of fruit a)
because its an array of refs, b) Java performs runtime checks on all array
writes)
have you considered allow a 'checked' keyword to allow a ref/array to sub class be passes as array/ref to superclass, and the same for redefinable members (basically implement a write barrier on checked items).
void func( inout Fruit f )
{
f = new Apple();
}
void func2( checked inout Fruit f )
{
f = new Apple();
}
void afunc( Fruit[] f )
{
f[0] = new Apple();
}
void afunc2( checked Fruit[] f )
{
f[0] = new Apple();
}
Banana b;
func( b ); // error (inout) ('out' would also require a check 'in' would
not)
func2( b ); // ok but will throw an exception
Banana[] ar;
afunc( ar ); // error unchecked array
afunc2( ar ); // ok but will throw an exception
allowing the programmer to determine the safety speed trade off and nothing to stop the compiler writing two versions of func2/afunc2 one with runtime checks when the compiler can not determine if the call is safe, and one fast version if it can.
from the original example useing A without specifing the type is considered as a 'checked' item so all writes to the templated member are runtime checked.
|
March 05, 2003 Re: DMD 0.58 release | ||||
---|---|---|---|---|
| ||||
Posted in reply to Mike Wynn | At the moment, I'm going to defer the virtual types based on the discussion here, as it's pretty obvious that a *lot* more thought needs to go into it. There are some more compelling things to do with D at the moment that have a clear path to getting it done. |
March 06, 2003 Re: DMD 0.58 release | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter | In article <b43dg1$rq7$1@digitaldaemon.com>, Walter says... > > >"Daniel Yokomiso" <daniel_yokomiso@yahoo.com.br> wrote in message news:b432o0$krg$1@digitaldaemon.com... >> It's only possible with global world analysis. Eiffel has such holes, >> and they are trying to close them now, at least some, in the ECMA >standard. >> I vote against such feature in D. It'll be very easy to produce correct ^^^^^^^ >code >> for it if there's no restriction. > >Hmm, you mean you are against the virtual type feature because you think it will be too easy to produce incorrect code? > Errr, yes. My mistake. With such feature (without the restrictions) it'll be easy to forget about covariant attribute type changes when using frameworks or other functions. I believe that's better safe than sorry. |
Copyright © 1999-2021 by the D Language Foundation