April 19, 2010 Re: templates | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On 04/19/2010 02:16 PM, Steven Schveighoffer wrote:
>
> What you are looking for is a conversion from compile-time interface to
> runtime interface. The only drawback is, you can't go backwards (from a
> runtime interface to a compile-time).
That hurts. The thing is, I'm eventually going to need to get that T back so I can access the non-common parts of it.
The T types already correspond to an enum, so the interface could look like
interface IW{
Type type();
int foo(int);
}
then whenever I want T, I can just test type and perform a cast.
Now I'm thinking of how to express that mapping in a centralized function or template or whatever, and I think I'm back where I started. Oh well. I'm probably going to have to write out each case longhand anyways.
It probably isn't important, but aren't dynamic casts rather expensive?
|
April 19, 2010 Re: templates | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | Won't the union balloon Wrapper's size to always be that of the largest inner struct that you use? |
April 19, 2010 Re: templates | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ellery Newcomer | Ellery Newcomer:
> Won't the union balloon Wrapper's size to always be that of the largest inner struct that you use?
Yes, all items in an array must have the same size. If you want items of different size you have to add a level of indirection, storing inside the array pointers to the structs. Then your structs can be of different size, and you need pointer casts, as I have written in another post.
Bye,
bearophile
|
April 20, 2010 Re: templates | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ellery Newcomer | On 19/04/2010 20:16, Ellery Newcomer wrote:
> Hello.
>
> Say I have a [struct] template T, which takes a param S.
>
> Any T!(S) satisfies a certain template constraint W, so I can use any
> T!(S) the same way. I want to be able to store heterogeneous T!(S) in a
> single list. Is there any good way to express the type for this?
Why not simply...
class C(O)
{
private O obj;
object next;
this(O obj)
{
this.obj = obj;
}
...
invariant()
{
assert(this.obj fulfills W);
}
...
}
|
April 20, 2010 Re: templates | ||||
---|---|---|---|---|
| ||||
Posted in reply to BLS | BLS Wrote:
> On 19/04/2010 20:16, Ellery Newcomer wrote:
> > Hello.
> >
> > Say I have a [struct] template T, which takes a param S.
> >
> > Any T!(S) satisfies a certain template constraint W, so I can use any
> > T!(S) the same way. I want to be able to store heterogeneous T!(S) in a
> > single list. Is there any good way to express the type for this?
>
> Why not simply...
>
> class C(O)
> {
> private O obj;
> object next;
> this(O obj)
> {
> this.obj = obj;
> }
> ...
> invariant()
> {
> assert(this.obj fulfills W);
> }
> ...
> }
W is a compile-time interface. this.obj is Object, so at compile time all you have are Object's methods.
So no, it can't simply be that.
-Steve
|
April 20, 2010 Re: templates | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ellery Newcomer | Ellery Newcomer Wrote: > On 04/19/2010 02:16 PM, Steven Schveighoffer wrote: > > > > What you are looking for is a conversion from compile-time interface to runtime interface. The only drawback is, you can't go backwards (from a runtime interface to a compile-time). > > That hurts. The thing is, I'm eventually going to need to get that T back so I can access the non-common parts of it. This is possible, via dynamic casting: IW x; if(auto wofT = cast(WByVal!T)x) { wofT._t.specializedMethod(); // need to expose _t in the class definition } If you need to figure out what type the IW is, you can do a switch on the classinfo. However, bottom line is, when you want to access a compile-time interface, you need to know about that type during compile time. So for instance if you add another type that can be wrapped by IW, you need to add another case statement for that type. Compile-time means the compiler has to know about everything, so there is no abstraction, everything must be concrete. RTTI can do some incredible things, and I hope D can join the ranks of languages like C# and Java with a full runtime reflection capabilities. > The T types already correspond to an enum, so the interface could look like > > interface IW{ > Type type(); > int foo(int); > } > > then whenever I want T, I can just test type and perform a cast. You can get this info via the classinfo, it's already there. > Now I'm thinking of how to express that mapping in a centralized function or template or whatever, and I think I'm back where I started. Oh well. I'm probably going to have to write out each case longhand anyways. Yes, each case must be explicitly handled. There is no generic way to do it! It is one of those things that seems like it should work, but if you ever try to solve it, you realize why it doesn't ;) > It probably isn't important, but aren't dynamic casts rather expensive? I wouldn't call them rather expensive, dynamic casts aren't particularly cheap, but they might be your only option. I would cache any dynamic cast so you aren't doing it over and over again. If you want the absolute best speed, you will have to implement your own type of "dynamic cast" instead of using D's class/interface system, similar to what bearophile stated. -Steve |
April 20, 2010 Re: templates | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ellery Newcomer | Ellery Newcomer:
> Won't the union balloon Wrapper's size to always be that of the largest inner struct that you use?
Beside using the array of struct-enums, or using an array of pointers I've explained in the other answer, there are other solutions, but they are even more complex, there are ways to create variable-sized items inside the "array" that becomes more like a memory arena for the structs.
Then you need ways to find your structs inside this array, there are many ways to do this, with various compromises between memory used and retrieval performance.
The minimum extra memory comes from scanning this arena linearly, because the tags tell you how much big each struct is, this has O(n) search. The max extra memory comes storing a second array of starting pointers that give you O(1) search. An intermediate solution is for example to add a skip list inside the array, with O(ln n) both in extra space and access time, etc.
But in most situations all this work is not necessary, unless you are in needs of space and performance are very demanding...
Bye,
bearophile
|
April 20, 2010 Re: templates | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer Attachments:
| On Mon, Apr 19, 2010 at 22:58, Steven Schveighoffer <schveiguy@yahoo.com>wrote:
>
> I'm not used to using interfaces in this way. What become the stored T
>> values when you cast the classes into IW to construct your array? I
>> suppose
>> they're lost?
>>
>
>
> Not sure what you mean...
>
What if the class has some value in it? In your code:
class WByVal(T) if (implementsW!T)
{
this(T val) {this._t = val;}
private T _t;
int foo(int x)
{
return _t.foo(x);
}
}
What happens to _t when I cast a WByVal to a IW?
|
April 20, 2010 Re: templates | ||||
---|---|---|---|---|
| ||||
Posted in reply to Philippe Sigaud | On Tue, 20 Apr 2010 02:01:23 -0400, Philippe Sigaud <philippe.sigaud@gmail.com> wrote:
> On Mon, Apr 19, 2010 at 22:58, Steven Schveighoffer <schveiguy@yahoo.com>wrote:
>
>>
>> I'm not used to using interfaces in this way. What become the stored T
>>> values when you cast the classes into IW to construct your array? I
>>> suppose
>>> they're lost?
>>>
>>
>>
>> Not sure what you mean...
>>
>
> What if the class has some value in it? In your code:
>
> class WByVal(T) if (implementsW!T)
> {
> this(T val) {this._t = val;}
> private T _t;
> int foo(int x)
> {
> return _t.foo(x);
> }
> }
>
> What happens to _t when I cast a WByVal to a IW?
Nothing, it's still there. Casting to an interface does nothing to the data. An interface is simply an abstracted set of functions that can be used to access any object that implements that interface.
It's the same as casting to a base class. Having a pointer to a base class, you don't have direct access to the data defined in the derived class, but the data is still there.
-Steve
|
Copyright © 1999-2021 by the D Language Foundation