Semantics of @disable
Is this how @disable is supposed to work (D2 code)? Is overriding a disabled function meaningful? import std.c.stdio: puts; class A { void foo() { puts(A.foo()); } } class B : A { //@disable override void foo(); // Linker error @disable override void foo() { puts(B.foo()); }; // OK } class C : B { override void foo() { puts(C.foo()); }; } void main() { A b = new B; b.foo(); // OK, Output: B.foo() B b2 = cast(B)b; // Compile-time Output: Error: function test.B.foo is not callable because it is annotated with @disable b2.foo(); C c = new C; c.foo(); // OK, Output: C.foo() } Bye and thank you, bearophile
Re: metaprogramming question
On 10-04-19 01:31 AM, BCS wrote: Hello Justin Spahr-Summers, On Mon, 19 Apr 2010 00:12:28 + (UTC), Graham Fawcett fawc...@uwindsor.ca wrote: Hi folks, I'd like to wrap a family of C functions that look like this: gboolean fooXXX(arg1, ..., argN, GError** err) Their signatures and arities vary, but they all have a GError** as their last argument. If a function returns false, then 'err' will be set to a relevant Error struct. I would like to write a wrapper that would let me call these functions sort of like this: check!(fooXXX(arg1, ..., argN)) where the 'check' expression would be equivalent to: GError* err; bool ok = fooXXX(arg1, ..., argN, err); if (!ok) throw new Exception((*err).message); Does D (2.0) offer a metaprogramming technique I could use to accomplish this -- particularly, to inject that 'err' argument into the tail of the fooXXX call? Thanks, Graham You can use some expression tuple magic to accomplish something like that: bool check(alias func, EL ...)() { GError* err; bool ok = func(EL, err); if (!ok) throw new Exception((*err).message); return ok; } // used like: check!(fooXXX, arg1, ..., argN); IIRC that should be: check!(fooXXX, argType1, ..., argTypeN)(arg1, ..., argN); See http://digitalmars.com/d/2.0/template.html#TemplateTupleParameter Or you can mangel that a bit: template check(alias func) { bool check(EL ...)() { GError* err; bool ok = func(EL, err); if (!ok) throw new Exception((*err).message); return ok; } } that should allow you to call it like: check!(fooXXX)(arg1, ..., argN); Remarkable! Thank you to everyone who responded. I can't wait to give these a try tonight. :) Cheers, Graham
templates
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?
Re: templates
Ellery Newcomer: 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? In D the templates with their arguments create a Nominative type system, so they are all seen as distinct types: http://en.wikipedia.org/wiki/Nominative_type_system So in D the standard, simpler and safer way to create a (flat) hierarchy of things that can be mixed in a container is to use the same strategy you use in Java, to create a base class/interface/abstract class, create a container of such base thing, and then populate it. If you don't want objects, and you want templated structs, then you have to work more, and your code will probably be less safe. In your situation you can create a common struct, it can contain several common fields, or just a tag, this is the minimal: enum FooTags { Tag1, Tag2, ... } struct BaseFoo { FooTags tag; // few common attributes // few common methods } (That BaseFoo can also be a template mixin, then you can mix in this template at the top of all your derived structs.) struct Foo1 { FooTags tag = FooTags.Tag1; ... } Then you have to read the tag and cast the pointer to the pointer of the correct type, in a switch if necessary... If your structs are allocated from the C heap, and you have only up to 8 or 16 different structs, you can even use a tagged pointer, but you also need an aligned malloc wrapper. This saves the 1 or or 2 or 4 bytes for the tag. Bye, bearophile
Re: templates
On Mon, 19 Apr 2010 14:16:03 -0400, Ellery Newcomer ellery-newco...@utulsa.edu 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? 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). This can be possible in runtime reflection systems, but the theory is that RTTI can be built from compile-time type info. Here is a quick-and-dirty solution, if you don't mind using classes/interfaces. You are going to need some sort of runtime interface in order to get this to work, classes/interfaces are not the leanest way to do this, but it should get the job done: The S is an extra complication that can be factored out, so let's forget about S for now. Let's assume W defines a single function int foo(int). Let's make a W interface: interface IW { int foo(int); } Now, we can define a class template to hold your values: class WByVal(T) if (implementsW!T) { this(T val) {this._t = val;} private T _t; int foo(int x) { return _t.foo(x); } } Maybe a helper function WByVal!(T) makeW(T)(T _t) { return new WByVal!(T)(_t); } Now you can easily convert a T to a IW with makeW, and by definition, any IW implements the W functions, so it can be used in anything that accepts W by constraint. So you can now form lists/arrays of IW objects to be used as needed. One other possibility is to use a union, but I think Variant might be better at that point. -Steve
Re: templates
On Mon, 19 Apr 2010 15:16:46 -0400, Steven Schveighoffer schvei...@yahoo.com wrote: On Mon, 19 Apr 2010 14:16:03 -0400, Ellery Newcomer ellery-newco...@utulsa.edu 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? 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). This can be possible in runtime reflection systems, but the theory is that RTTI can be built from compile-time type info. Here is a quick-and-dirty solution, if you don't mind using classes/interfaces. You are going to need some sort of runtime interface in order to get this to work, classes/interfaces are not the leanest way to do this, but it should get the job done: The S is an extra complication that can be factored out, so let's forget about S for now. Let's assume W defines a single function int foo(int). Let's make a W interface: interface IW { int foo(int); } Now, we can define a class template to hold your values: class WByVal(T) if (implementsW!T) Whoops! Forgot the interface! class WByVal(T) : IW if (implementsW!T) -Steve
Re: templates
Ellery Newcomer wrote: I want to be able to store heterogeneous T!(S) in a single list std.boxer or std.variant may be useful: http://digitalmars.com/d/2.0/phobos/std_boxer.html http://digitalmars.com/d/2.0/phobos/std_variant.html Ali
Re: Code speed and C++
Joseph Wakeling: I took a little time last night and wrote up a C++ version that I'll take a look at this, I was away for few days. Bye, bearophile
Re: templates
On Mon, Apr 19, 2010 at 21:20, Steven Schveighoffer schvei...@yahoo.comwrote: Here is a quick-and-dirty solution, if you don't mind using classes/interfaces. (snip) 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? Does that mean that if we have a bunch of T (all different types),you map a call to makeW on it, get back a bunch of WByVal!T (all different types), cast them to IW and... what? erase the types? Philippe
Re: templates
On Mon, Apr 19, 2010 at 21:52, Ali Çehreli acehr...@yahoo.com wrote: Ellery Newcomer wrote: I want to be able to store heterogeneous T!(S) in a single list std.boxer or std.variant may be useful: http://digitalmars.com/d/2.0/phobos/std_boxer.html http://digitalmars.com/d/2.0/phobos/std_variant.html Ali But how do you get back what was stored inside a Variant without any indication as to what it was initially? As far as I get it, Variant is useful to have a variable that can be assigned with many other variables of different types during its lifetime. I also regularly want to use it to store _one_ thing, anything, to get it back later. But then I'm at a loss as to how crack open the Variant afterwards, without storing some sort of type information somewhere.
Re: templates
On Mon, 19 Apr 2010 16:52:40 -0400, Philippe Sigaud philippe.sig...@gmail.com wrote: On Mon, Apr 19, 2010 at 21:20, Steven Schveighoffer schvei...@yahoo.comwrote: Here is a quick-and-dirty solution, if you don't mind using classes/interfaces. (snip) 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... Does that mean that if we have a bunch of T (all different types),you map a call to makeW on it, get back a bunch of WByVal!T (all different types), cast them to IW and... what? erase the types? What I had in mind was: struct S { int foo(int x) { return x * 2; } } struct S2 { int foo(int x) { return x + 2; } } void main() { S s1; S2 s2; IW[] ws; ws ~= makeW(s1); ws ~= makeW(s2); assert(ws[0].foo(3) == 6); assert(ws[1].foo(3) == 5); } does this help? -Steve
Re: templates
Steven Schveighoffer: What I had in mind was: struct S { int foo(int x) { return x * 2; } } struct S2 { int foo(int x) { return x + 2; } } void main() { S s1; S2 s2; IW[] ws; ws ~= makeW(s1); ws ~= makeW(s2); assert(ws[0].foo(3) == 6); assert(ws[1].foo(3) == 5); } does this help? A possible solution, this code is just an idea that needs improvements, it's not generic: struct S1 { int foo(int x) { return x * 2; } } struct S2 { int foo(int x) { return x + 2; } } enum TypeTag { TS1, TS2 } struct Wrapper { TypeTag tag; union { S1 s1; S2 s2; } int foo(int x) { final switch(this.tag) { case TypeTag.TS1: return s1.foo(x); case TypeTag.TS2: return s2.foo(x); } } } Wrapper makeW(T)(T s) if (is(T == S1) || is(T == S2)) { static if (is(T == S1)) { Wrapper result = Wrapper(TypeTag.TS1); result.s1 = s; return result; } else static if (is(T == S2)) { Wrapper result = Wrapper(TypeTag.TS2); result.s2 = s; return result; } else assert(0); } void main() { S1 s1; S2 s2; Wrapper[] ws; ws ~= makeW(s1); ws ~= makeW(s2); assert(ws[0].foo(3) == 6); assert(ws[1].foo(3) == 5); } There are several other ways to solve this problem. This version is a bit nicer because it contains no pointer casts. Languages that have a tagged union (like Cyclone) need quite less code here, but probably D2 can be used to remove some of that code duplication. Bye, bearophile
Re: templates
Won't the union balloon Wrapper's size to always be that of the largest inner struct that you use?
Re: templates
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?
Re: templates
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
ctfe library
Are there any good libraries for ctfe/code generation? I don't know, things like parsing support for compile time strings, string formatting, type - string My project seems to be growing ctfe, and it's all horribly hacky and ugly code.
Re: templates
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); } ... }
Re: templates
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
Re: templates
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