template instantiation
///Hello, i'm trying to implement d compiler and i've problems with some template corner cases. class Type{} class Foo(T : const T){ alias X = T; } alias Bar(T : Foo!Ts, Ts...) = Ts[0]; pragma(msg, "Foo1: ", Foo!(immutable Type).X);//Foo1: Type pragma(msg, "Foo2: ", Foo!(Type).X); //Foo2: Type pragma(msg, "Bar: ", Bar!(Foo!(Type))); //Bar: immutable(Type) Last pragma attempted to extract template parameters from 'Foo!(Type)' but since Foo!(immutable Type) == Foo!(Type) and Foo!(immutable Type) was instantiated first, it extracted wrong type. If we change order of 1. and 2. pragma, result of 3. pragma will be Type and not immutable(Type). Is this a bug?
Template instantiation
Got the following code: public LuaState wrapClass (T) (T instance) { auto ptr = cast (T *) newUserdata ( (T *).sizeof); *ptr = instance; loadClassMetatable (typeid(T).toString); setMetatable (-2); return this; } Am I right in assuming that a different wrapClass will be created in the final executable for each template instantiation (e.g. calls with class A,B,C,... instances) and would thus bloat up the executable a bit when used with many classes? Apart from that, couldn't you just use wrapClass (Object instance)? In the end each class instance pointer takes up the same amount of memory?!
"extern" template instantiation
Hi everyone, This is going to be a silly question. I have the following files: -- heavy.d -- import std.regex; enum r = ctRegex!(r"^(\w+)\s+([a-zA-Z0-9/]+)\?a=(\w+)&b=(\w+)&c=(\w+)([&\D+=\w+)]*)&y=([0-9A-Fa-z]+)&z=([0-9A-Fa-z]+)$"); -- main.d -- import heavy; void main() {} -- test.d -- import heavy; void test() {} So I had a Makefile, and hit compile. *BAM* 1m40s latter, I switched from GDC to DMD, and updated my dmd to bleeding edge. I though it might help because of: http://d.puremagic.com/issues/show_bug.cgi?id=11284 $ dmd DMD64 D Compiler v2.064-devel-b12d171 But it didn't (time make): dmd -debug -c main.d -ofobjs/debug//main.o dmd -debug -c heavy.d -ofobjs/debug//heavy.o dmd -debug -c test.d -ofobjs/debug//test.o - Linking bfake real0m19.893s user0m11.092s sys 0m2.416s With the import commented out (and make clean'ed): dmd -debug -c main.d -ofobjs/debug//main.o dmd -debug -c heavy.d -ofobjs/debug//heavy.o dmd -debug -c test.d -ofobjs/debug//test.o - Linking bfake real0m5.636s user0m4.124s sys 0m0.872s So I thought of: public alias typeof(ctRegex!(my-super-long-string)) APIRegex; in a .di file, but I get a linker error, and it stills need to instantiate the template anyway. Can anyone point me to the right way to do this ? Thanks!
Re: template instantiation
On Thursday, 19 May 2016 at 20:14:48 UTC, vit wrote: Is this a bug? Yes. I've filed a report: https://issues.dlang.org/show_bug.cgi?id=16050
Recursive template instantiation
I'm pretty sure that this code should compile (https://dpaste.dzfl.pl/cf1e1ee6ef4b): struct A(T) { ~this() { char[T.sizeof] data; } } struct B(T) { A!T foo; } struct C { B!C bar; } void main() { C c; } But it doesn't: /d300/f416.d(3): Error: struct f416.C no size because of forward reference /d300/f416.d(12): Error: template instance f416.B!(C) error instantiating Notice that the same C++ code compiles without problems: template struct A { ~A() { char data[sizeof(T)]; } }; template struct B { A foo; }; struct C { B bar; }; int main() { C c; } A simple recursion is compiled successfully (https://dpaste.dzfl.pl/5a8ff73bfa88): struct A(T) { ~this() { char[T.sizeof] data; } } struct C { A!C bar; } void main() { C c; }
template instantiation question
I have three modules a.d, b.d, and c.d: file a.d:``` module i.a; import i.c, i.b; final class A { public: void foo() { a.transmogrify(); } S!void a; } ``` -- file b.d:``` module i.b; import i.a, i.c; class B { public: S!void b; } ``` -- file c.d:``` module i.c; struct C {} struct S(T) { C transmogrify() { return C(); } } ``` -- When these modules compiled separately, I assume, both a.o and b.o contain a definition of i.c.S!void.S.transmogrify() instance. Is this correct? If so, how is the symbol redefinition resolved when the three object files are linked into a single executable?
template instantiation problems
I'm trying to understand issue 17441 [1]. I reduced it (including Phobos) to the following (and added some message to point out the problem): test.d: --- alias parentOf(alias sym) = __traits(parent, sym); template packageName(alias T) { pragma(msg, "IN: ", T.stringof); static if (__traits(compiles, parentOf!T)) enum parent = packageName!(parentOf!T); else enum string parent = null; static if (T.stringof[0..8] == "package ") enum packageName = (parent? parent ~ '.' : "") ~ T.stringof[8 .. $]; else enum packageName = parent; } void main() { import mod0 = foo.baz; import mod1 = foo; pragma(msg, "mod0: ",mod0.stringof); pragma(msg, "mod1: ",mod1.stringof); pragma(msg, "A"); enum a = packageName!mod0; pragma(msg, "B"); enum b = packageName!mod1; pragma(msg, "C"); static assert(a == "foo"); static assert(b == ""); // Error: static assert: "foo" == "" is false } --- foo/baz.d: --- module foo.baz; --- foo/package.d: --- module foo; --- When compiling with $> dmd test.d I get: --- mod0: module baz mod1: module foo A IN: module baz IN: package foo B C test.d(32): Error: static assert: "foo" == "" is false --- This clearly shows, that packageName is only instatiated once at top level although mod0 and mod1 are two different things (at least their stringof produces different results) and therefore should be instantiated twice. Now I don't know if this is a bug in DMD or I should know something I do not know... Can you help me? [1] https://issues.dlang.org/show_bug.cgi?id=17441
Re: Template instantiation
On Fri, Mar 20, 2009 at 11:35 AM, Trass3r wrote: > Got the following code: > > public LuaState wrapClass (T) (T instance) > { > auto ptr = cast (T *) newUserdata ( (T *).sizeof); > *ptr = instance; > > loadClassMetatable (typeid(T).toString); > setMetatable (-2); > return this; > } > > Am I right in assuming that a different wrapClass will be created in the > final executable for each template instantiation (e.g. calls with class > A,B,C,... instances) and would thus bloat up the executable a bit when used > with many classes? Yes. > Apart from that, couldn't you just use wrapClass (Object instance)? In the > end each class instance pointer takes up the same amount of memory?! > I'd say yes. It doesn't look like there's any need for a template here. It wouldn't be (Object*).sizeof when allocating the userdata, though; just Object.sizeof.
Template instantiation without (...)
Which bit of the spec for template instantiation is it that allows the last two lines of the following to compile and work? import std.stdio; struct A { int a; } template Thingie(T) { static if (is(T == int)) enum Thingie = 1; else enum Thingie = 0; } void main() { writefln("%d", Thingie!(int)); writefln("%d", Thingie!int); writefln("%d", Thingie!A); }
Re: "extern" template instantiation
Using `enum` with ctRegex is discouraged because it is a dumb copy-paste upon every enum usage. I'd recommend to use global variable initialized during compile-time: ``` auto r = ctRegex!(r"^(\w+)\s+([a-zA-Z0-9/]+)\?a=(\w+)&b=(\w+)&c=(\w+)([&\D+=\w+)]*)&y=([0-9A-Fa-z]+)&z=([0-9A-Fa-z]+)$"); ``` Though it is pretty complex ctRegex and compiling it is a good stress test for any compiler :)
Re: "extern" template instantiation
On Wednesday, 23 October 2013 at 11:58:17 UTC, Dicebot wrote: Using `enum` with ctRegex is discouraged because it is a dumb copy-paste upon every enum usage. I'd recommend to use global variable initialized during compile-time: ``` auto r = ctRegex!(r"^(\w+)\s+([a-zA-Z0-9/]+)\?a=(\w+)&b=(\w+)&c=(\w+)([&\D+=\w+)]*)&y=([0-9A-Fa-z]+)&z=([0-9A-Fa-z]+)$"); ``` Though it is pretty complex ctRegex and compiling it is a good stress test for any compiler :) Using auto was my first try. Unfortunately it has the same issue (slighly faster, but still "dumb C/P". So far I didn't find any way to tell the compiler not to compile it if I'm not using it (aside from versions). As the type itself takes ages to compile, any reasonable-sized project with few regexes will not be able to use ctRegex in dev mode. I suppose there's no way to create a function that returns a generic ctRegex object without loosing the advantages ? Note: The regex might seems complex, but actually isn't. It parses an home-made REST API based on query authentification: http://broadcast.oreilly.com/2009/12/principles-for-standardized-rest-authentication.html . To me it sounded like a simple use case.
Re: "extern" template instantiation
24-Oct-2013 20:30, Mathias LANG пишет: On Wednesday, 23 October 2013 at 11:58:17 UTC, Dicebot wrote: Using `enum` with ctRegex is discouraged because it is a dumb copy-paste upon every enum usage. I'd recommend to use global variable initialized during compile-time: ``` auto r = ctRegex!(r"^(\w+)\s+([a-zA-Z0-9/]+)\?a=(\w+)&b=(\w+)&c=(\w+)([&\D+=\w+)]*)&y=([0-9A-Fa-z]+)&z=([0-9A-Fa-z]+)$"); ``` Though it is pretty complex ctRegex and compiling it is a good stress test for any compiler :) Using auto was my first try. Unfortunately it has the same issue (slighly faster, but still "dumb C/P". So far I didn't find any way to tell the compiler not to compile it if I'm not using it (aside from versions). As the type itself takes ages to compile, any reasonable-sized project with few regexes will not be able to use ctRegex in dev mode. I suppose there's no way to create a function that returns a generic ctRegex object without loosing the advantages ? Something to the extent of auto getMeARegex() { static r = ctRegex!(r"^(\w+)\s+([a-zA-Z0-9/]+)\?a=(\w+)&b=(\w+)&c=(\w+)([&\D+=\w+)]*)&y=([0-9A-Fa-z]+)&z=([0-9A-Fa-z]+)$"); return r; } _Might_ work. Failing that make it an 0-arg template: auto getMeARegex()(){ ... } Note: The regex might seems complex, but actually isn't. It parses an home-made REST API based on query authentification: http://broadcast.oreilly.com/2009/12/principles-for-standardized-rest-authentication.html . To me it sounded like a simple use case. -- Dmitry Olshansky
template instantiation in D
Code is http://dpaste.dzfl.pl/73bd7002. And I can't understand why compiler instantiates SimpleFSM.execTransition!(), line #30 - I expected it would be instantiated only if template parameters were wrong, but it occurs always. Does compiler instantiates ALL possible template specialization?
Weird template instantiation problem
Hi, I've found a strange problem, and I'm not sure if it's a bug. To give a bit of background, I'm implementing a multi-threaded producer-consumer where the next work item to be picked depends not only on the "waiting queue", but also on what else is being run (and potentially where) at the same moment, so things like "sort"'ing the queue won't probably work, because I don't think you use a delegate as a predicate for "sort" (that's what I think it would be needed to get the extra context information). The idea here is that the "chooser" function returns the *index* of the work item to be picked. So, the reduced problem looks like this (I've removed the extra information about the running jobs to make the example simpler): ``` enum defaultChooser(T) = function size_t(T[] queue) { return 0; }; struct S(T, size_t function(T[]) chooser = defaultChooser!T) { } void main() { S!int s; } ``` this fails and I get this: Error: template instance S!int does not match template declaration S(T, ulong function(T[]) chooser = defaultChooser!T) If instead of returning the index the actual item is returned, it works! ``` enum defaultChooser(T) = function T(T[] queue) { return queue[0]; }; struct S(T, T function(T[]) chooser = defaultChooser!T) { } void main() { S!int s; } ``` As you can see, the only change is the type the function returns, but I don't see how it should make any difference. Also, changing from "enum" to "static immutable", or even removing the "enum" and directly embedding the function literal doesn't seem to make any difference. Any ideas on what might be going on??
Re: Recursive template instantiation
Is this a bug?
Re: Recursive template instantiation
On Monday, 13 March 2017 at 22:05:24 UTC, Jack Applegame wrote: Is this a bug? No it's not struct C { B!C; } is an error. Howto compute C ? <--\ let's check the members; | The member needs a template. | Howto compute the template ? | let's compute the parameters. | What is the first Parameter ? | Its C. | Howoto compute C---/
Re: Recursive template instantiation
On 03/13/2017 03:26 PM, Jack Applegame wrote: I'm pretty sure that this code should compile (https://dpaste.dzfl.pl/cf1e1ee6ef4b): struct A(T) { ~this() { char[T.sizeof] data; } } struct B(T) { A!T foo; } struct C { B!C bar; } void main() { C c; } But it doesn't: /d300/f416.d(3): Error: struct f416.C no size because of forward reference /d300/f416.d(12): Error: template instance f416.B!(C) error instantiating It compiles when it's a normal method instead of a destructor: struct A(T) { void m() { char[T.sizeof] data; } } /* ... rest as above ... */ I don't see how the destructor makes a difference. Soo, bug?
Re: Recursive template instantiation
On Monday, 13 March 2017 at 22:59:36 UTC, ag0aep6g wrote: On 03/13/2017 03:26 PM, Jack Applegame wrote: I'm pretty sure that this code should compile (https://dpaste.dzfl.pl/cf1e1ee6ef4b): struct A(T) { ~this() { char[T.sizeof] data; } } struct B(T) { A!T foo; } struct C { B!C bar; } void main() { C c; } But it doesn't: /d300/f416.d(3): Error: struct f416.C no size because of forward reference /d300/f416.d(12): Error: template instance f416.B!(C) error instantiating It compiles when it's a normal method instead of a destructor: struct A(T) { void m() { char[T.sizeof] data; } } /* ... rest as above ... */ I don't see how the destructor makes a difference. Soo, bug? Try to use m.
Re: Recursive template instantiation
On 03/14/2017 12:02 AM, Stefan Koch wrote: On Monday, 13 March 2017 at 22:59:36 UTC, ag0aep6g wrote: [...] struct A(T) { void m() { char[T.sizeof] data; } } /* ... rest as above ... */ I don't see how the destructor makes a difference. Soo, bug? Try to use m. Works no problem? struct A(T) { void m() { char[T.sizeof] data; import std.stdio; writeln(T.sizeof); } } struct B(T) { A!T foo; } struct C { B!C bar; } void main() { C c; c.bar.foo.m(); } Prints "1".
Re: Recursive template instantiation
On 03/13/2017 11:58 PM, Stefan Koch wrote: On Monday, 13 March 2017 at 22:05:24 UTC, Jack Applegame wrote: Is this a bug? No it's not struct C { B!C; } is an error. Howto compute C ? <--\ let's check the members; | The member needs a template. | Howto compute the template ? | let's compute the parameters. | What is the first Parameter ? | Its C. | Howoto compute C---/ I don't think that's it. Here's a variant where B is not instantiated with C: struct A() { ~this() { enum s = C.sizeof; } } struct B() { A!() foo; } struct C { B!() bar; } How to compute C? Check members. For member `B!() bar;`, resolve `B!()`. Check members of `B!()`. For member `A!() foo;` resolve `A!()`. Check members of `A!()`. No members => size = 0 (or rather 1, I guess). Bubble up. But the compiler seems to get confused by the destructor. I guess it incorrectly(?) sees a need to analyze C again before it can finish up `A!()`?
Re: template instantiation question
On 03/18/2015 11:03 AM, Dmitri Makarov wrote: > When these modules compiled separately, I assume, both a.o and b.o > contain a definition of i.c.S!void.S.transmogrify() instance. That is very likely but I played with different three files for a while and failed to see that. > how is the symbol redefinition resolved when the three object > files are linked into a single executable? There are different kinds of symbols. For example, the following command on a Linux console will show that template instances are weak symbols (it is not an error to have one or more weak symbols). $ nm b.o | grep transmogrify W _D1c8__T1CTvZ1C12transmogrifyMFNaNbNiNfZi 'man nm' tells us that W indicates a weak symbol: "W" "w" The symbol is a weak symbol that has not been specifically tagged as a weak object symbol. When a weak defined symbol is linked with a normal defined symbol, the normal defined symbol is used with no error. When a weak undefined symbol is linked and the symbol is not defined, the value of the symbol is determined in a system-specific manner without error. On some systems, uppercase indicates that a default value has been specified. Ali
Re: template instantiation question
On Wednesday, 18 March 2015 at 18:26:07 UTC, Ali Çehreli wrote: $ nm b.o | grep transmogrify W _D1c8__T1CTvZ1C12transmogrifyMFNaNbNiNfZi What compiler do you use? For me, neither a.o nor b.o contain transmogrify definition: $ dmd -c -Ix x/i/a.d $ nm a.o | grep trans U _D1i1c8__T1STvZ1S12transmogrifyMFNaNbNiNfZS1i1c1C $ dmd -c -Ix x/i/b.d $ nm b.o | grep trans $
Re: template instantiation question
(My earlier response seems to be lost; trying one more time.) On 03/18/2015 12:09 PM, Dmitri Makarov wrote: > On Wednesday, 18 March 2015 at 18:26:07 UTC, Ali Çehreli wrote: >> $ nm b.o | grep transmogrify >> W _D1c8__T1CTvZ1C12transmogrifyMFNaNbNiNfZi > > What compiler do you use? dmd git head. I used simpler files: // a.d module a; import c; import b; auto foo() { auto c = C!void(); return c.transmogrify(); } void main() { assert(.foo() == b.foo()); } // b.d module b; import c; auto foo() { auto c = C!void(); return c.transmogrify(); } // c.d module c; struct C(T) { int transmogrify() { return 42; } } Then I built the program like this: $ dmd a.d -c $ dmd b.d -c $ dmd c.d -c $ dmd a.o b.o c.o Ali
Re: template instantiation problems
On 10.01.20 18:27, berni44 wrote: This clearly shows, that packageName is only instatiated once at top level although mod0 and mod1 are two different things (at least their stringof produces different results) and therefore should be instantiated twice. Now I don't know if this is a bug in DMD or I should know something I do not know... Can you help me? import m1 = foo.baz; import m2 = foo; alias p = __traits(parent, m1); pragma(msg, m1.stringof); /* "module baz", ok */ pragma(msg, m2.stringof); /* "module foo", ok */ pragma(msg, p.stringof); /* "package foo", ok */ enum e(alias thing) = thing.stringof; pragma(msg, e!m1); /* "module baz", ok */ pragma(msg, e!m2); /* "module foo", ok */ pragma(msg, e!p); /* "module foo", wat?? */ If you switch the last two lines around, you get "package foo" twice. The compiler apparently thinks that m2 (module foo) and p (package foo) are the same thing when used as a template argument. So it reuses the previous result. There's a similar issue with values: https://issues.dlang.org/show_bug.cgi?id=14501
Re: template instantiation problems
On Friday, 10 January 2020 at 18:31:59 UTC, ag0aep6g wrote: import m1 = foo.baz; import m2 = foo; alias p = __traits(parent, m1); pragma(msg, m1.stringof); /* "module baz", ok */ pragma(msg, m2.stringof); /* "module foo", ok */ pragma(msg, p.stringof); /* "package foo", ok */ enum e(alias thing) = thing.stringof; pragma(msg, e!m1); /* "module baz", ok */ pragma(msg, e!m2); /* "module foo", ok */ pragma(msg, e!p); /* "module foo", wat?? */ Thanks for your test case. https://github.com/dlang/dmd/pull/10724
Re: Template instantiation without (...)
Steve Teale Wrote: > Which bit of the spec for template instantiation is it that allows the > last two lines of the following to compile and work? > > import std.stdio; > > > struct A > { > int a; > } > > template Thingie(T) > { > static if (is(T == int)) > enum Thingie = 1; > else > enum Thingie = 0; > } > > void main() > { > writefln("%d", Thingie!(int)); > writefln("%d", Thingie!int); > writefln("%d", Thingie!A); > } I suppose it's the part of the spec you're about to write a patch for.
Re: Template instantiation without (...)
> I suppose it's the part of the spec you're about to write a patch for. I guess so. It was discussed on one of the forums back in October 2008. I guess it got implemented but never made the documentation.
Re: Template instantiation without (...)
> I suppose it's the part of the spec you're about to write a patch for. Twas at: http://www.digitalmars.com/d/archives/digitalmars/D/ Template_instantiation_syntax_77507.html#N77507
Reporting unsupported template instantiation
http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=114518 Is there a way to report a custom error message for unsupported template instantiations?
0 cost template instantiation
I have a template function that all it does is given a symbol, it loads a dll for its type + its name: ``` void loadSymbol(alias s, string symName = "")() { static if(symName == "") s = cast(typeof(s))_loadSymbol(_dll, (s.stringof~"\0").ptr); else s = cast(typeof(s))_loadSymbol(_dll, (symName~"\0").ptr); } ``` The main problem is that this function is costing 2KB per instantiation, which is something pretty high. Specially if I inline, there is almost no cost when compared to its inline version. Trying to use pragma(inline, true) didn't do anything too. If I understood correctly, mixin template would be some way to actually inline anything. The problem is that I can't have any kind of expression inside it, so, that's the only way I could think in how to do it. Optimization seems to don't take care of that behaviour too. I would like to know which approach could I take for making something like C's #define for that. As this function could be really rewritten as a macro if I were coding in C, the cost is too high for a function that would be only a syntactic sugar
Weird template instantiation speed?
While working on some new bindings, I've discovered that if `opAssign` in a struct template "`BindingTempl(T)`" has the return type "`BindingTempl!T` then it adds about 4 seconds to the compile time per instantiation of `BindingTempl`. The added compile time is much lower if a function other than `opAssign` returns `BindingTempl!T`. Is opAssign a particularly bad operator to overload in templates or something?
template instantiation --- having trouble therewith
template Dptr( T, U...) { alias T delegate( U args) Dptr; } Dptr!(T,U) muddle( T, U...)( Dptr!(T,U) f) { return f; //or make another delegate in real code } unittest { import std.stdio; int x = 3; int scale( int s) { return x * s; } Dptr!(int,int) f = muddle( &scale); writeln( f(7)); } The above technique seemed natural to me, but I get this message from dmd: p1.d(15): Error: template p1.muddle does not match any function template declaration. Candidates are: p1.d(7):p1.muddle(T, U...)(Dptr!(T, U) f) p1.d(15): Error: template p1.muddle(T, U...)(Dptr!(T, U) f) cannot deduce template function from argument types !()(int delegate(int)) and if I use muddle!(int,int) instead it doesn't help. This is likely a misunderstanding on my part --- please show me how to sort this out.
Re: template instantiation in D
27.09.2012 22:48, Druzhinin Alexandr пишет: Code is http://dpaste.dzfl.pl/73bd7002. And I can't understand why compiler instantiates SimpleFSM.execTransition!(), line #30 - I expected it would be instantiated only if template parameters were wrong, but it occurs always. Does compiler instantiates ALL possible template specialization? Oh, I've just understood my problem - because possibility of execTransition!() calling can be known only in run-time, compiler should instantionates it too, just in case. Good thing this newsgroup is, good thing )))
Re: Weird template instantiation problem
On 06/12/2017 05:31 PM, Arafel wrote: Hi, I've found a strange problem, and I'm not sure if it's a bug. To give a bit of background, I'm implementing a multi-threaded producer-consumer where the next work item to be picked depends not only on the "waiting queue", but also on what else is being run (and potentially where) at the same moment, so things like "sort"'ing the queue won't probably work, because I don't think you use a delegate as a predicate for "sort" (that's what I think it would be needed to get the extra context information). The idea here is that the "chooser" function returns the *index* of the work item to be picked. So, the reduced problem looks like this (I've removed the extra information about the running jobs to make the example simpler): ``` enum defaultChooser(T) = function size_t(T[] queue) { return 0; }; struct S(T, size_t function(T[]) chooser = defaultChooser!T) { } void main() { S!int s; } ``` this fails and I get this: Error: template instance S!int does not match template declaration S(T, ulong function(T[]) chooser = defaultChooser!T) If instead of returning the index the actual item is returned, it works! ``` enum defaultChooser(T) = function T(T[] queue) { return queue[0]; }; struct S(T, T function(T[]) chooser = defaultChooser!T) { } void main() { S!int s; } ``` As you can see, the only change is the type the function returns, but I don't see how it should make any difference. Also, changing from "enum" to "static immutable", or even removing the "enum" and directly embedding the function literal doesn't seem to make any difference. Any ideas on what might be going on?? Even more strange: ``` enum defaultChooser(T) = function size_t(T[] queue) { return 0; }; static assert (is (typeof(defaultChooser!int) == size_t function(int[] queue) pure nothrow @nogc @safe)); struct S(T, size_t function(T[] queue) pure nothrow @nogc @safe chooser) { } void main() { S!(int, defaultChooser!int) s; } ``` The static assert passes (tried with the wrong values), yet I get this error message: Error: template instance S!(int, function ulong(int[] queue) => 0LU) does not match template declaration S(T, ulong function(T[] queue) pure nothrow @nogc @safe chooser) Am I missing something fundamental? But then, why does it work if I change the return type in the template parameter?
Re: Weird template instantiation problem
more funny compiler messages: alias xx = size_t function (int[]); struct S1(T, typeof(xx) X) {} void main() { S1!(int, defaultChooser!int) s; } Error: type uint function(int[]) is not an expression but: struct S2(T, typeof(defaultChooser!T) chooser=defaultChooser!T) {} void main() { S2!int s; } Error: undefined identifier T error messages are totally random (and why `typeof()` is not allowed there?)
Re: Weird template instantiation problem
p.s.: while i understand the technical reason for second error message, it is still random and confusing.
Re: Weird template instantiation problem
On Monday, 12 June 2017 at 19:23:10 UTC, ketmar wrote: p.s.: while i understand the technical reason for second error message, it is still random and confusing. I think the reason for the typeof problem is that it works with expressions, not with types (so, typeof (int) is also not valid), and the alias resolves ultimately to a type. I actually found a workaround for the original issue: ``` enum defaultChooser(T) = function size_t(T[] queue) { return 0; }; struct S(T, alias chooser = defaultChooser!int) if (is(typeof(chooser) : size_t function(T[]))) { } void main() { S!(int, defaultChooser!int) s; } ``` This works, but strangely if I try "==" instead of ":" in the template condition, then it fails again. Honestly I don't know why it makes a difference, I guess attribute inference might be at fault... but in the version with the "static assert" I was explicitly checking them, and they apparently matched... Also, this is just a(n ugly) workaround, and there might be side effects of using an alias parameter that I'm not aware of... and more importantly, I still think the original version should work! ;-)
Re: Weird template instantiation problem
Arafel wrote: I actually found a workaround for the original issue: yeah, sorry for not proposing a workaround: i thought that you already did it, and now you're just interested why the original code doesn't work. ;-) i think that this is a bug (or, rather, unimplemented feature).
Re: Weird template instantiation problem
Well, I had kind of found a workaround (changing the return type to return the element and not the index) which I didn't like too much (what if there are duplicates?). Now that I've found a "proper" workaround well, I'm still interested in knowing the reason, if possible, or if it's a bug. On 06/12/2017 09:49 PM, ketmar wrote: yeah, sorry for not proposing a workaround: i thought that you already did it, and now you're just interested why the original code doesn't work. ;-) i think that this is a bug (or, rather, unimplemented feature).
Re: Weird template instantiation problem
On 6/12/17 11:31 AM, Arafel wrote: As you can see, the only change is the type the function returns, but I don't see how it should make any difference. Also, changing from "enum" to "static immutable", or even removing the "enum" and directly embedding the function literal doesn't seem to make any difference. Any ideas on what might be going on?? Looks like a bug to me. Please file. -Steve
Using attributes inside template instantiation
I'm trying to declare format for database record in compile time. I consider to use attributes fo this. Can I do something similar to this code? struct RecordFormat(T) {} alias Format = RecordFormat!( @("cool") int ); pragma( msg, Format ); void main() { } Or I want something strange that is not supported by language? For now I don't understand whether UDA are a part of types or they are a part of variable instance definition or something different (3rd dimension)). For example 'const int' is a type but what @attribute int is? Can it be considered as separate type or it could be binded to definition of variable only? @attribute int number; I failed to alias type alias coolInt = @("cool") int; But I can alias const int alias constInt = const int; I think I understood something wrong about attributes.
__traits(compiles) and template instantiation
I've been playing around with __traits and I find myself confused on one aspect. In the code below, I was testing whether some templates would compile given types. For the most part it works as I would expect. I think I get why the third one works with foo!(int). My guess is that it assumed that U is the same as T and both are int. However, that wouldn't make sense with the last one where I use bar!(int). In that one it's basically ignoring the second template constraint. So I don't understand what's going on for that last line to compile. To confirm I wasn't crazy, I get an error with alias bar_ = bar!(int); import std.traits : isNumeric; import std.range : isInputRange; void foo(T, U)(T x, U y) if (isNumeric!T && isNumeric!U) { } void bar(T, U)(T x, U y) if (isNumeric!T && isInputRange!U) { } void main() { assert(__traits(compiles, foo!(int, int))); //I get this assert(!__traits(compiles, foo!(bool, bool))); //I get this assert(__traits(compiles, foo!(int))); //I think I get this assert(__traits(compiles, bar!(int, int[]))); //I get this assert(!__traits(compiles, bar!(int, int)));//I get this assert(__traits(compiles, bar!(int))); //I don't get this }
Re: Reporting unsupported template instantiation
Hello Kagamin, http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmar s.D&article_id=114518 Is there a way to report a custom error message for unsupported template instantiations? template Foo(T) { static assert(Chcek!(T), "message"); ... } template Bar(T) if (is( T == U)) { ... } template Bar(T) { static assert(false, "message"); } -- ... <
Re: 0 cost template instantiation
On Thursday, 30 September 2021 at 01:09:47 UTC, Hipreme wrote: I have a template function that all it does is given a symbol, it loads a dll for its type + its name: ``` void loadSymbol(alias s, string symName = "")() { static if(symName == "") s = cast(typeof(s))_loadSymbol(_dll, (s.stringof~"\0").ptr); else s = cast(typeof(s))_loadSymbol(_dll, (symName~"\0").ptr); } ``` If symName is always a string literal, then you don't need to append a "\0"; string literals always have a trailing NUL after them, and they autoconvert to const(char)[] so you don't need the .ptr either.
Re: 0 cost template instantiation
On Thursday, 30 September 2021 at 01:09:47 UTC, Hipreme wrote: I have a template function that all it does is given a symbol, it loads a dll for its type + its name: ``` void loadSymbol(alias s, string symName = "")() { static if(symName == "") s = cast(typeof(s))_loadSymbol(_dll, (s.stringof~"\0").ptr); else s = cast(typeof(s))_loadSymbol(_dll, (symName~"\0").ptr); } ``` The main problem is that this function is costing 2KB per instantiation, which is something pretty high. Specially if I inline, there is almost no cost when compared to its inline version. Trying to use pragma(inline, true) didn't do anything too. cant you just use a regular functions ? loading happens at runtime right ?
Re: 0 cost template instantiation
On Thursday, 30 September 2021 at 01:56:42 UTC, Basile B. wrote: On Thursday, 30 September 2021 at 01:09:47 UTC, Hipreme wrote: I have a template function that all it does is given a symbol, it loads a dll for its type + its name: ``` void loadSymbol(alias s, string symName = "")() { static if(symName == "") s = cast(typeof(s))_loadSymbol(_dll, (s.stringof~"\0").ptr); else s = cast(typeof(s))_loadSymbol(_dll, (symName~"\0").ptr); } ``` The main problem is that this function is costing 2KB per instantiation, which is something pretty high. Specially if I inline, there is almost no cost when compared to its inline version. Trying to use pragma(inline, true) didn't do anything too. cant you just use a regular functions ? loading happens at runtime right ? The entire reason to having that function is having that syntax which would pretty much do the monkey's job for me: Instead of writing myFunction = cast(typeof(myFunction))_loadSymbol(_dll, "myFunction"); I could write loadSymbol!myFunction; But if no other way is found of doing that, I will do the massive rewriting. Anyway, I don't think the problem is not in the way I'm doing, but the output, as that template could easily be inlined
Re: 0 cost template instantiation
On Thursday, 30 September 2021 at 02:02:19 UTC, Hipreme wrote: On Thursday, 30 September 2021 at 01:56:42 UTC, Basile B. wrote: On Thursday, 30 September 2021 at 01:09:47 UTC, Hipreme wrote: I have a template function that all it does is given a symbol, it loads a dll for its type + its name: ``` void loadSymbol(alias s, string symName = "")() { static if(symName == "") s = cast(typeof(s))_loadSymbol(_dll, (s.stringof~"\0").ptr); else s = cast(typeof(s))_loadSymbol(_dll, (symName~"\0").ptr); } ``` The main problem is that this function is costing 2KB per instantiation, which is something pretty high. Specially if I inline, there is almost no cost when compared to its inline version. Trying to use pragma(inline, true) didn't do anything too. cant you just use a regular functions ? loading happens at runtime right ? The entire reason to having that function is having that syntax which would pretty much do the monkey's job for me: Instead of writing myFunction = cast(typeof(myFunction))_loadSymbol(_dll, "myFunction"); I could write loadSymbol!myFunction; But if no other way is found of doing that, I will do the massive rewriting. Anyway, I don't think the problem is not in the way I'm doing, but the output, as that template could easily be inlined well ok. Maybe try to see if overloads void loadSymbol(alias s)() void loadSymbol(alias s, string symName)() helps. That save the static if. In addition there's the null sentinel that can save a bit of memory, as you've been suggested.
Re: 0 cost template instantiation
On Thursday, 30 September 2021 at 01:09:47 UTC, Hipreme wrote: I have a template function that all it does is given a symbol, it loads a dll for its type + its name: ``` void loadSymbol(alias s, string symName = "")() { static if(symName == "") s = cast(typeof(s))_loadSymbol(_dll, (s.stringof~"\0").ptr); else s = cast(typeof(s))_loadSymbol(_dll, (symName~"\0").ptr); } ``` The main problem is that this function is costing 2KB per instantiation, which is something pretty high. Specially if I inline, there is almost no cost when compared to its inline version. Trying to use pragma(inline, true) didn't do anything too. If I understood correctly, mixin template would be some way to actually inline anything. The problem is that I can't have any kind of expression inside it, so, that's the only way I could think in how to do it. Optimization seems to don't take care of that behaviour too. I would like to know which approach could I take for making something like C's #define for that. As this function could be really rewritten as a macro if I were coding in C, the cost is too high for a function that would be only a syntactic sugar I could reduce by almost 100kb of code by instead of using the former option, I use: ``` void loadSymbols(Ts...)() { static foreach(s; Ts) s = cast(typeof(s))_loadSymbol(_dll, s.stringof); } ``` Then instead of making a call for each one, I just pass a list of templates, this would only create one instantiation per need. I do still don't think that this should be the answer, as the alias problem is not yet solved. It takes a lot of size for functions that could be only syntactic sugar, where C would be a lot better
Re: 0 cost template instantiation
On Thursday, 30 September 2021 at 02:02:19 UTC, Hipreme wrote: Instead of writing myFunction = cast(typeof(myFunction))_loadSymbol(_dll, "myFunction"); I could write loadSymbol!myFunction; But if no other way is found of doing that, I will do the massive rewriting. --- void function() x; void load(void* thing, string name) { // this lhs cast is the magic, the rhs cast unneeded in reality cuz GetProcAddress returns void* naturally * cast(void**) thing = cast(void*) 0xdeadbeef; } void main() { // no cast here but yes repeated name load(&x, "foo"); // casts needed here just to do the comparison assert(cast(void*) x == cast(void*) 0xdeadbeef); } --- A little void casting inside the function can do the trick. You will have to pass the name separately though. im off to bed ttyl
Re: 0 cost template instantiation
On Thursday, 30 September 2021 at 02:09:50 UTC, Hipreme wrote: I could reduce by almost 100kb of code by instead of using the former option, I use: yes this is what id o you can list the Ts in an interface too. see my simpledisplay.d `interface GL` for example I do still don't think that this should be the answer, as the alias problem is not yet solved. It takes a lot of size for functions that could be only syntactic sugar, where C would be a lot better well it must generate functions for each thing there by definition and since you call them at runtime it can't cut them out either. so this is kinda meh you MIGHT be able to do a tempalte that forwards to a single runtime function though. but i seriously need to g2g maybe can look tomorrow
Re: 0 cost template instantiation
On Thursday, 30 September 2021 at 01:44:57 UTC, jfondren wrote: On Thursday, 30 September 2021 at 01:09:47 UTC, Hipreme wrote: I have a template function that all it does is given a symbol, it loads a dll for its type + its name: ``` void loadSymbol(alias s, string symName = "")() { static if(symName == "") s = cast(typeof(s))_loadSymbol(_dll, (s.stringof~"\0").ptr); else s = cast(typeof(s))_loadSymbol(_dll, (symName~"\0").ptr); } ``` If symName is always a string literal, then you don't need to append a "\0"; string literals always have a trailing NUL after them, and they autoconvert to const(char)[] so you don't need the .ptr either. Playing around with this, with a mock-up of your code, doesn't change object size at all. Is the actual source available, that you're seeing this with?
Re: 0 cost template instantiation
On Thursday, 30 September 2021 at 02:22:35 UTC, jfondren wrote: On Thursday, 30 September 2021 at 01:44:57 UTC, jfondren wrote: On Thursday, 30 September 2021 at 01:09:47 UTC, Hipreme wrote: I have a template function that all it does is given a symbol, it loads a dll for its type + its name: ``` void loadSymbol(alias s, string symName = "")() { static if(symName == "") s = cast(typeof(s))_loadSymbol(_dll, (s.stringof~"\0").ptr); else s = cast(typeof(s))_loadSymbol(_dll, (symName~"\0").ptr); } ``` If symName is always a string literal, then you don't need to append a "\0"; string literals always have a trailing NUL after them, and they autoconvert to const(char)[] so you don't need the .ptr either. Playing around with this, with a mock-up of your code, doesn't change object size at all. Is the actual source available, that you're seeing this with? https://github.com/MrcSnm/HipremeEngine/tree/hotload/api You may try messing at the module api.graphics.g2d.renderer2d There is a function called initG2D Try changing it from loadSymbols to each one loadSymbol. You can just dub at the folder api.
Re: 0 cost template instantiation
On Thursday, 30 September 2021 at 02:31:50 UTC, Hipreme wrote: https://github.com/MrcSnm/HipremeEngine/tree/hotload/api You may try messing at the module api.graphics.g2d.renderer2d There is a function called initG2D Try changing it from loadSymbols to each one loadSymbol. You can just dub at the folder api. The version I checked out, 2874073b54, doesn't have a loadSymbols. As provided, loadSymbol without the "static if": 965K libhipengine_api.a with `mixin(loadSymbol("name"))` instead of a template: 749K libhipengine_api.a https://gist.github.com/jrfondren/d776ccffb105f464b53c53712656a1d3 That's probably disappointing, since it's a much less pleasant interface, but what you could do is take the both entire `extern(C) void function() beginSprite; ... loadSymbol!beginSprite;` blocks and put them in one string literal that you process with a function and mixin once. Now instead of an annoying macro alternative you have a DSL for DLL-extern functions.
Re: 0 cost template instantiation
On Thursday, 30 September 2021 at 03:13:28 UTC, jfondren wrote: As provided, loadSymbol without the "static if": 965K libhipengine_api.a with `mixin(loadSymbol("name"))` instead of a template: 749K libhipengine_api.a The difference goes down to 66K vs. 60K with `dub -brelease --compiler=gdc`. ldc's not as slim but still much better than dmd, and -brelease is actually much less significant. So dmd's the main culprit for the bloat here. huh. But since you have importPaths-ldc perhaps you weren't using dmd to begin with.
Re: 0 cost template instantiation
On Thursday, 30 September 2021 at 03:21:51 UTC, jfondren wrote: On Thursday, 30 September 2021 at 03:13:28 UTC, jfondren wrote: As provided, loadSymbol without the "static if": 965K libhipengine_api.a with `mixin(loadSymbol("name"))` instead of a template: 749K libhipengine_api.a The difference goes down to 66K vs. 60K with `dub -brelease --compiler=gdc`. ldc's not as slim but still much better than dmd, and -brelease is actually much less significant. So dmd's the main culprit for the bloat here. huh. But since you have importPaths-ldc perhaps you weren't using dmd to begin with. Yup. The mixin(loadSymbol("")) seems the best way to do. I believe that should be the option for loading separated symbols while loadSymbols version is the best for loading a lot of symbols(IDK how expensive is mixing a lot of functions) as it costs 1KB per instantiation. I'm actually using DMD and LDC, dmd compiles a bit faster, but I use ldc for deploying it. Never used GDC.
Re: Weird template instantiation speed?
On 7/9/23 7:54 AM, IchorDev wrote: While working on some new bindings, I've discovered that if `opAssign` in a struct template "`BindingTempl(T)`" has the return type "`BindingTempl!T` then it adds about 4 seconds to the compile time per instantiation of `BindingTempl`. The added compile time is much lower if a function other than `opAssign` returns `BindingTempl!T`. Is opAssign a particularly bad operator to overload in templates or something? This is probably a bug somewhere, 4 seconds is too much. A reduced test case would be helpful. But I wanted to note, inside a struct template, the template name (by itself) is equivalent to the current instantiation. So just returning `BindingTempl` would be equivalent, and might not trigger this problem. See if that helps. -Steve
Re: Weird template instantiation speed?
On Sunday, 9 July 2023 at 14:49:39 UTC, Steven Schveighoffer wrote: This is probably a bug somewhere, 4 seconds is too much. A reduced test case would be helpful. But I wanted to note, inside a struct template, the template name (by itself) is equivalent to the current instantiation. So just returning `BindingTempl` would be equivalent, and might not trigger this problem. See if that helps. -Steve Thank you for letting me know about being able to use `BindingTempl`, I had no idea! Unfortunately it doesn't mitigate the compile times, though. I forgot to mention, it only happens when specifying `-O` with DMD. LDC and GDC compile the same thing almost instantly. Boiling it down to a simple test is tough. If you remove a lot of components the struct template depends on then the compile time is too fast for anything to be noticeable. I think the issue is some kind of snowball-effect. If anyone wants to try to reproduce this issue: 1. Download [this exact commit](https://github.com/ichordev/bindbc-imgui/tree/65d02d68e4188250c948147a04a5820de3479a44) of the WIP BindBC-ImGui repo. (the newer commits won't compile) 2. Edit dub.selections.json to change `"bindbc-common"`'s version to `"0.0.6"`. 3. Run: ``` dmd -extern-std=c++11 -lib -O -version=BindImGui_Static -Isource/ -I~/.dub/packages/bindbc-common/0.0.6/bindbc-common/source/ source/bindbc/imgui/config.d source/bindbc/imgui/package.d source/imgui/impl.d source/imgui/package.d -v ``` 4. Now, remove `-O` from the dmd command. Blink and you'll miss it compiling!
Re: template instantiation --- having trouble therewith
On Tuesday, 3 September 2013 at 03:49:52 UTC, Carl Sturtivant wrote: template Dptr( T, U...) { alias T delegate( U args) Dptr; } Dptr!(T,U) muddle( T, U...)( Dptr!(T,U) f) { return f; //or make another delegate in real code } unittest { import std.stdio; int x = 3; int scale( int s) { return x * s; } Dptr!(int,int) f = muddle( &scale); writeln( f(7)); } The above technique seemed natural to me, but I get this message from dmd: p1.d(15): Error: template p1.muddle does not match any function template declaration. Candidates are: p1.d(7):p1.muddle(T, U...)(Dptr!(T, U) f) p1.d(15): Error: template p1.muddle(T, U...)(Dptr!(T, U) f) cannot deduce template function from argument types !()(int delegate(int)) and if I use muddle!(int,int) instead it doesn't help. This is likely a misunderstanding on my part --- please show me how to sort this out. I'm confused as to what you're trying to do... your example code is equivalent to import std.stdio; int x = 3; int scale( int s) { return x * s; } auto f = &scale; writeln( f(7) );
Re: template instantiation --- having trouble therewith
I'm confused as to what you're trying to do... your example code is equivalent to import std.stdio; int x = 3; int scale( int s) { return x * s; } auto f = &scale; writeln( f(7) ); No it isn't according to dmd. My code is a minimal piece that produces the same error as some real code. The higher order generic function muddle in the real code is supposed to transform one delegate into another, but I still get the template problem if muddle is the identity function (given here). My example code isn't equivalent to the above according to the compiler. Why is that? And how can I make it work?
Re: template instantiation --- having trouble therewith
Carl Sturtivant wrote: > No it isn't according to dmd. dmd does not express this. according to > p1.d(15): Error: [...] dmd "cannot deduce" that `Dptr!(T, U)' might be equal to `int delegate(int)' -manfred
Re: template instantiation --- having trouble therewith
Carl Sturtivant wrote: > How do I fix this? maybe it is currently not fixable because of restrictions in the deduction algorithm. Obviously the deduction works if the instantion of the template is replaced by a symbol by `alias T delegate( U) Dptr;' or similar. -manfred
Re: template instantiation --- having trouble therewith
On Tuesday, 3 September 2013 at 13:42:44 UTC, Manfred Nowak wrote: Carl Sturtivant wrote: No it isn't according to dmd. dmd does not express this. according to p1.d(15): Error: [...] dmd "cannot deduce" that `Dptr!(T, U)' might be equal to `int delegate(int)' -manfred I understood that. How do I fix this? Writing muddle!(int,int) in the unit test so there's no type inference needed gives the same error message.
Re: template instantiation --- having trouble therewith
Carl Sturtivant wrote: > Writing muddle!(int,int) [...] > gives the same error message. Not entirely true: template muddle( T, U...){ alias T delegate( U) Dptr; auto muddle1( T, U...)( Dptr f) { return f; //or make another delegate in real code } alias muddle1!( T, U) muddle; } unittest { import std.stdio; int x = 3; int scale( int s) { return x * s; } auto f= muddle!( int, int)( &scale); writeln( f(7)); } -manfred
Re: template instantiation --- having trouble therewith
Carl Sturtivant wrote: > is supposed to transform one delegate into another Then please declare the template parameters to be delegates: U muddle( T, U)( T f) { uint g( int fp){ return cast(uint)( 5* f( fp)); } auto gP= &g; return gP; } unittest { import std.stdio; int x = 3; int scale( int s) { return x * s; } auto f= muddle!( int delegate( int), uint delegate( int))( &scale); writeln( f(7)); } // no deduction problems -manfred
Re: template instantiation --- having trouble therewith
On Tuesday, 3 September 2013 at 17:25:12 UTC, Manfred Nowak wrote: Carl Sturtivant wrote: Writing muddle!(int,int) [...] gives the same error message. Not entirely true: template muddle( T, U...){ alias T delegate( U) Dptr; auto muddle1( T, U...)( Dptr f) { return f; //or make another delegate in real code } alias muddle1!( T, U) muddle; } unittest { import std.stdio; int x = 3; int scale( int s) { return x * s; } auto f= muddle!( int, int)( &scale); writeln( f(7)); } Can you point me at some documentation that explains this behavior?
Re: template instantiation --- having trouble therewith
On Tuesday, 3 September 2013 at 13:42:44 UTC, Manfred Nowak wrote: Carl Sturtivant wrote: No it isn't according to dmd. dmd does not express this. according to p1.d(15): Error: [...] dmd "cannot deduce" that `Dptr!(T, U)' might be equal to `int delegate(int)' Indeed, dmd doesn't know the equivalence, and therefore won't compile my code.
Re: template instantiation --- having trouble therewith
On Tuesday, 3 September 2013 at 21:52:58 UTC, Manfred Nowak wrote: Carl Sturtivant wrote: is supposed to transform one delegate into another Then please declare the template parameters to be delegates: U muddle( T, U)( T f) { uint g( int fp){ return cast(uint)( 5* f( fp)); } auto gP= &g; return gP; } unittest { import std.stdio; int x = 3; int scale( int s) { return x * s; } auto f= muddle!( int delegate( int), uint delegate( int))( &scale); writeln( f(7)); } But I want some inference. In the real code the relevant delegates will have lots of long messy signatures that have already been declared. And in your example above, I want the arguments of the delegates in general to be a type tuple, because any delegate may be passed.
Re: template instantiation --- having trouble therewith
On Tuesday, 3 September 2013 at 17:25:12 UTC, Manfred Nowak wrote: Carl Sturtivant wrote: Writing muddle!(int,int) [...] gives the same error message. Not entirely true: template muddle( T, U...){ alias T delegate( U) Dptr; auto muddle1( T, U...)( Dptr f) { return f; //or make another delegate in real code } alias muddle1!( T, U) muddle; } unittest { import std.stdio; int x = 3; int scale( int s) { return x * s; } auto f= muddle!( int, int)( &scale); writeln( f(7)); } -manfred This technique does what I want if there's a single parameter to the delegate. I'll explore from here; thanks for all the examples. Carl.
Re: template instantiation --- having trouble therewith
On Tuesday, 3 September 2013 at 11:51:37 UTC, Carl Sturtivant wrote: I'm confused as to what you're trying to do... your example code is equivalent to import std.stdio; int x = 3; int scale( int s) { return x * s; } auto f = &scale; writeln( f(7) ); No it isn't according to dmd. My code is a minimal piece that produces the same error as some real code. The higher order generic function muddle in the real code is supposed to transform one delegate into another, but I still get the template problem if muddle is the identity function (given here). My example code isn't equivalent to the above according to the compiler. Why is that? And how can I make it work? Ok, that makes more sense. The reason why it doesn't work is that you're effectively asking the compiler to work backwards from {the type of the delegate passed to muddle} to {the type parameters that would have to be used in Dptr to generate that delegate type}. I'm no expert on type-deduction algorithms, but I seriously doubt that's a solvable problem in the general case, especially considering that the definition of Dptr could contain string mixins etc. In the general case, all code is forwards-only. Anyhow, it's easy to work around: import std.traits : ReturnType, ParameterTypeTuple; template Dptr( T, U...) { alias T delegate( U args) Dptr; } auto muddle( DT)( DT f) { alias T = ReturnType!f; alias U = ParameterTypeTuple!f; //use T and U return f; //or make another delegate in real code } unittest { import std.stdio; int x = 3; int scale( int s) { return x * s; } Dptr!(int,int) f = muddle( &scale); writeln( f(7)); }
Re: template instantiation --- having trouble therewith
On Thursday, 5 September 2013 at 09:00:27 UTC, John Colvin wrote: On Tuesday, 3 September 2013 at 11:51:37 UTC, Carl Sturtivant wrote: I'm confused as to what you're trying to do... your example code is equivalent to import std.stdio; int x = 3; int scale( int s) { return x * s; } auto f = &scale; writeln( f(7) ); No it isn't according to dmd. My code is a minimal piece that produces the same error as some real code. The higher order generic function muddle in the real code is supposed to transform one delegate into another, but I still get the template problem if muddle is the identity function (given here). My example code isn't equivalent to the above according to the compiler. Why is that? And how can I make it work? Ok, that makes more sense. The reason why it doesn't work is that you're effectively asking the compiler to work backwards from {the type of the delegate passed to muddle} to {the type parameters that would have to be used in Dptr to generate that delegate type}. I'm no expert on type-deduction algorithms, but I seriously doubt that's a solvable problem in the general case, especially considering that the definition of Dptr could contain string mixins etc. In the general case, all code is forwards-only. Anyhow, it's easy to work around: import std.traits : ReturnType, ParameterTypeTuple; template Dptr( T, U...) { alias T delegate( U args) Dptr; } auto muddle( DT)( DT f) { alias T = ReturnType!f; alias U = ParameterTypeTuple!f; //use T and U return f; //or make another delegate in real code } unittest { import std.stdio; int x = 3; int scale( int s) { return x * s; } Dptr!(int,int) f = muddle( &scale); writeln( f(7)); } Having said that, in the case where you explicitly set the template parameters to muddle I think it *should* work and is probably a bug (or at least a simple enhancement) that it doesn't.
Re: template instantiation --- having trouble therewith
On Thursday, 5 September 2013 at 09:11:06 UTC, John Colvin wrote: On Thursday, 5 September 2013 at 09:00:27 UTC, John Colvin wrote: On Tuesday, 3 September 2013 at 11:51:37 UTC, Carl Sturtivant wrote: I'm confused as to what you're trying to do... your example code is equivalent to import std.stdio; int x = 3; int scale( int s) { return x * s; } auto f = &scale; writeln( f(7) ); No it isn't according to dmd. My code is a minimal piece that produces the same error as some real code. The higher order generic function muddle in the real code is supposed to transform one delegate into another, but I still get the template problem if muddle is the identity function (given here). My example code isn't equivalent to the above according to the compiler. Why is that? And how can I make it work? Ok, that makes more sense. The reason why it doesn't work is that you're effectively asking the compiler to work backwards from {the type of the delegate passed to muddle} to {the type parameters that would have to be used in Dptr to generate that delegate type}. I'm no expert on type-deduction algorithms, but I seriously doubt that's a solvable problem in the general case, especially considering that the definition of Dptr could contain string mixins etc. In the general case, all code is forwards-only. Anyhow, it's easy to work around: import std.traits : ReturnType, ParameterTypeTuple; template Dptr( T, U...) { alias T delegate( U args) Dptr; } auto muddle( DT)( DT f) { alias T = ReturnType!f; alias U = ParameterTypeTuple!f; //use T and U return f; //or make another delegate in real code } unittest { import std.stdio; int x = 3; int scale( int s) { return x * s; } Dptr!(int,int) f = muddle( &scale); writeln( f(7)); } Having said that, in the case where you explicitly set the template parameters to muddle I think it *should* work and is probably a bug (or at least a simple enhancement) that it doesn't. I filed a bug report for it http://d.puremagic.com/issues/show_bug.cgi?id=10969
Re: template instantiation --- having trouble therewith
On Thursday, 5 September 2013 at 09:33:00 UTC, John Colvin wrote: On Thursday, 5 September 2013 at 09:11:06 UTC, John Colvin wrote: On Thursday, 5 September 2013 at 09:00:27 UTC, John Colvin wrote: On Tuesday, 3 September 2013 at 11:51:37 UTC, Carl Sturtivant wrote: I'm confused as to what you're trying to do... your example code is equivalent to import std.stdio; int x = 3; int scale( int s) { return x * s; } auto f = &scale; writeln( f(7) ); No it isn't according to dmd. My code is a minimal piece that produces the same error as some real code. The higher order generic function muddle in the real code is supposed to transform one delegate into another, but I still get the template problem if muddle is the identity function (given here). My example code isn't equivalent to the above according to the compiler. Why is that? And how can I make it work? Ok, that makes more sense. The reason why it doesn't work is that you're effectively asking the compiler to work backwards from {the type of the delegate passed to muddle} to {the type parameters that would have to be used in Dptr to generate that delegate type}. I'm no expert on type-deduction algorithms, but I seriously doubt that's a solvable problem in the general case, especially considering that the definition of Dptr could contain string mixins etc. In the general case, all code is forwards-only. Anyhow, it's easy to work around: import std.traits : ReturnType, ParameterTypeTuple; template Dptr( T, U...) { alias T delegate( U args) Dptr; } auto muddle( DT)( DT f) { alias T = ReturnType!f; alias U = ParameterTypeTuple!f; //use T and U return f; //or make another delegate in real code } unittest { import std.stdio; int x = 3; int scale( int s) { return x * s; } Dptr!(int,int) f = muddle( &scale); writeln( f(7)); } Having said that, in the case where you explicitly set the template parameters to muddle I think it *should* work and is probably a bug (or at least a simple enhancement) that it doesn't. I filed a bug report for it http://d.puremagic.com/issues/show_bug.cgi?id=10969 and only 26.5 mins after posting the bug, there's a pull request to fix it: https://github.com/D-Programming-Language/dmd/pull/2526 That's what I call service :p
Re: Using attributes inside template instantiation
UDA's are compile-time metadata associated with a specific declaration. So in something like: @foo int x; The @foo is attached to x, but is not part of the type.
Re: Using attributes inside template instantiation
On Wed, Jun 25, 2014 at 05:10:06PM +, Chris Nicholson-Sauls via Digitalmars-d-learn wrote: > UDA's are compile-time metadata associated with a specific > declaration. So in something like: > > @foo int x; > > The @foo is attached to x, but is not part of the type. The term "attribute" is a bit confusing, especially since "property" is also used in the language to refer to something completely different. A better term is perhaps "annotation". The @foo is an annotation on x, but its type is just int. Furthermore, the @foo annotation on it only exists at compile-type; it doesn't exist at runtime. The purpose is really to enhance compile-time introspection and metaprogramming; but what the OP wants seems to be something else altogether. Sadly, the "attribute" terminology has stuck, and is unlikely to change. T -- What do you get if you drop a piano down a mineshaft? A flat minor.
Re: Using attributes inside template instantiation
On Wednesday, 25 June 2014 at 17:21:21 UTC, H. S. Teoh via Digitalmars-d-learn wrote: The term "attribute" is a bit confusing, especially since "property" is also used in the language to refer to something completely different. A better term is perhaps "annotation". The @foo is an annotation on x, but its type is just int. Agree whole-heartedly. I usually introduce people to the idea by referring to them as annotations, which they understand quickly, then later tell them that it's called an attribute because of reasons no one knows. I get funny looks, but at least they comprehend it. I'm not so sure it's too late to get the terminology changed, though, and I sincerely hope it will.
Re: Using attributes inside template instantiation
But if I write @("hello") struct Hello {} so all of the variables that have type Hello will have attribute @("hello") like come type qualifier because attribute is a part of declaration of Hello. Do I understand correctly?
Re: Using attributes inside template instantiation
On Thursday, 26 June 2014 at 07:11:03 UTC, Uranuz wrote: But if I write @("hello") struct Hello {} so all of the variables that have type Hello will have attribute @("hello") like come type qualifier because attribute is a part of declaration of Hello. Do I understand correctly? No, it is only the symbol Hello that will have the attribute @("hello"). Attributes are attached to symbols, not types or values.
Implicit Function Template Instantiation (IFTI) Question
When using a template with multiple functions within it, is it possible to access the underlying functions directly? Not sure I am missing anything, but what works when the functions are named differently from the headline template doesn't work when the functions are named the same. import std.stdio: writeln; import std.traits: isFunction; template foo(T) { void foo(U)(U x) { writeln("here0"); } void foo(U, V)(U x, V y) { writeln("there0"); } } template bar(T) { void baz(U)(U x) { writeln("here1"); } void baz(U, V)(U x, V y) { writeln("there1"); } } void foobar(T)(T x) {} void main() { foo!int.foo!(float, double)(1f, 2.0); //Error: template foo(U)(U x) does not have property foo writeln(isFunction!(foo!int)); //prints false, as expected b/c not smart enough to look through writeln(isFunction!(foo!int.foo!float)); //Error: template identifier foo is not a member of template onlineapp.foo!int.foo(U)(U x) writeln(isFunction!(foo!int.foo!(float, double))); //ditto bar!int.baz!(float, double)(1f, 2.0); //prints there1 writeln(isFunction!(bar!int.baz!(float, double))); //prints true writeln(isFunction!(foobar!int)); //prints true }
Re: __traits(compiles) and template instantiation
On Thursday, 7 April 2016 at 20:31:12 UTC, jmh530 wrote: I've been playing around with __traits and I find myself confused on one aspect. In the code below, I was testing whether some templates would compile given types. For the most part it works as I would expect. I think I get why the third one works with foo!(int). My guess is that it assumed that U is the same as T and both are int. However, that wouldn't make sense with the last one where I use bar!(int). In that one it's basically ignoring the second template constraint. So I don't understand what's going on for that last line to compile. To confirm I wasn't crazy, I get an error with alias bar_ = bar!(int); import std.traits : isNumeric; import std.range : isInputRange; void foo(T, U)(T x, U y) if (isNumeric!T && isNumeric!U) { } void bar(T, U)(T x, U y) if (isNumeric!T && isInputRange!U) { } void main() { assert(__traits(compiles, foo!(int, int))); //I get this assert(!__traits(compiles, foo!(bool, bool))); //I get this assert(__traits(compiles, foo!(int))); //I think I get this assert(__traits(compiles, bar!(int, int[]))); //I get this assert(!__traits(compiles, bar!(int, int)));//I get this assert(__traits(compiles, bar!(int))); //I don't get this } Neither the third nor sixth lines should be true. alias wrongfoo = foo!int; /* Error: template instance foo!int does not match template declaration foo(T, U)(T x, U y) if (isNumeric!T && isNumeric!U) */ alias rightfoo = foo!(int, int); /* ok */ File a DMD bug. (Also, you can use static assert here to check the assertions at build-time instead of run-time)
Re: __traits(compiles) and template instantiation
On Thursday, 7 April 2016 at 21:36:37 UTC, Alex Parrill wrote: On Thursday, 7 April 2016 at 20:31:12 UTC, jmh530 wrote: I've been playing around with __traits and I find myself confused on one aspect. In the code below, I was testing whether some templates would compile given types. For the most part it works as I would expect. [...] Neither the third nor sixth lines should be true. alias wrongfoo = foo!int; /* Error: template instance foo!int does not match template declaration foo(T, U)(T x, U y) if (isNumeric!T && isNumeric!U) */ alias rightfoo = foo!(int, int); /* ok */ File a DMD bug. (Also, you can use static assert here to check the assertions at build-time instead of run-time) is(typeof()) gives the expected results: import std.traits : isNumeric; import std.range : isInputRange; void foo(T, U)(T x, U y) if (isNumeric!T && isNumeric!U) { } void bar(T, U)(T x, U y) if (isNumeric!T && isInputRange!U) { } unittest { static assert(is(typeof(foo!(int, int; //I get this static assert(!is(typeof(foo!(bool, bool; //I get this static assert(!is(typeof(foo!(int; //I think I get this static assert(is(typeof(bar!(int, int[];//I get this static assert(!is(typeof(bar!(int, int; //I get this static assert(!is(typeof(bar!(int; //I don't get this } (note well I have changed the assertion 3 and 6). There must be a subtle difference between __traits(compile,...) and is(typeof()). Does "compiles" mean that you've get something but that this thing is not always of a valid type ?
Re: __traits(compiles) and template instantiation
It looks like the bug has already been reported. There are a few associated with __traits(compiles), but this one seems most relevant: https://issues.dlang.org/show_bug.cgi?id=3448 It also suggests that this is relevant: https://issues.dlang.org/show_bug.cgi?id=965
Template instantiation and string vs const char[]
I have this piece of code: template somet(R...) { static if (R.length) { string somet = "[\n"~R[0]~"\n" ~ somet!(R[1..R.length]) ~ "]\n"; } else string somet = ""; } void main() { writeln(somet!("name","tame")); writeln(somet!"name"); } When I compile it, it generates the error message "static variable somet cannot be read at compile time". When I replace 'string' with 'const char[]', it works. Can anyone explain why this happens? Thanks. Regards
Re: Implicit Function Template Instantiation (IFTI) Question
On 4/27/20 1:19 PM, jmh530 wrote: When using a template with multiple functions within it, is it possible to access the underlying functions directly? Not sure I am missing anything, but what works when the functions are named differently from the headline template doesn't work when the functions are named the same. import std.stdio: writeln; import std.traits: isFunction; template foo(T) { void foo(U)(U x) { writeln("here0"); } void foo(U, V)(U x, V y) { writeln("there0"); } } template bar(T) { void baz(U)(U x) { writeln("here1"); } void baz(U, V)(U x, V y) { writeln("there1"); } } void foobar(T)(T x) {} void main() { foo!int.foo!(float, double)(1f, 2.0); //Error: template foo(U)(U x) does not have property foo foo!int aliases to the template foo's inside, so you are already in there. In reality, you should want to use foo!int!(float, double), but that does not parse. You can do: alias x = foo!int; x!(float, double)(...) or you can just use IFTI: foo!int(1f, 2.0); writeln(isFunction!(foo!int)); //prints false, as expected b/c not smart enough to look through No, because the template hasn't been instantiated. Note that isFunction!(foobar) prints false also. writeln(isFunction!(foo!int.foo!float)); //Error: template identifier foo is not a member of template onlineapp.foo!int.foo(U)(U x) An eponymous template is equivalent to the members that have the same name. There is no way to access the template namespace (this was changed some time ago). with x definition above: writeln(isFunction!(x!float)); // true writeln(isFunction!(foo!int.foo!(float, double))); //ditto bar!int.baz!(float, double)(1f, 2.0); //prints there1 writeln(isFunction!(bar!int.baz!(float, double))); //prints true writeln(isFunction!(foobar!int)); //prints true } Generally it's just fine to do foo(T, U, V) and dispense with the double templates, as IFTI will take care of the other two. The main reason to have nested templates is when you need to bind the explicit template parameters to a variadic, and the IFTI parameters to something else. i.e.: template foo(T...) { void foo(U...)(U args) {... } } foo!(int, char, bool)(1, 2, 3) -> foo!(int, char, bool)!(int, int, int)(1, 2, 3); I hope this clears it up a bit. -Steve
Re: Implicit Function Template Instantiation (IFTI) Question
On Mon, Apr 27, 2020 at 05:19:35PM +, jmh530 via Digitalmars-d-learn wrote: > When using a template with multiple functions within it, is it > possible to access the underlying functions directly? Yes, but only if the template is not eponymous. > Not sure I am missing anything, but what works when the functions are > named differently from the headline template doesn't work when the > functions are named the same. Yes, when the template is eponymous, the name of the template becomes the name of the eponymous member, and thus effectively hides the other members from outside access. This is actually useful when you want to write a template function with internal implementation details that outside code cannot access no matter what. It's like a little encapsulation unit locked away behind the public-facing eponymous member. I've used this on a few occasions when I wanted template implementation details to be invisible even to other code inside the same module. (Interesting note: you can even stick unittests inside the template block to test internal details, while still keeping said details away from prying eyes in the rest of the module. :-P) T -- Doubtless it is a good thing to have an open mind, but a truly open mind should be open at both ends, like the food-pipe, with the capacity for excretion as well as absorption. -- Northrop Frye
Re: Implicit Function Template Instantiation (IFTI) Question
On Monday, 27 April 2020 at 17:40:06 UTC, Steven Schveighoffer wrote: [snip] Thanks for that. Very detailed. In terms of a use case, we just added a center function to mir [1]. It can take an alias to a function. I wanted to add a check that the arity of the function was 1, but it turned out that I couldn't do that for mean [2] because it has a similar structure as what I posted and arity relies on isCallable, which depends on isFunction. [1] http://mir-algorithm.libmir.org/mir_math_stat.html#.center [2] http://mir-algorithm.libmir.org/mir_math_stat.html#.mean
Shared, ref, arrays, and reserve template instantiation
When I add the "shared" attribute to an array, I am no longer able to call reserve because the template won't instantiate: Error: template object.reserve cannot deduce function from argument types !()(shared(int[]), int), candidates are: /dlang/dmd/linux/bin64/../../src/druntime/import/object.d(4091): object.reserve(T)(ref T[] arr, size_t newcapacity) 1. Shared modifies the type, so the template does not match. Even casting does not seem to work however. Is there something about shared that makes it unable to be taken by reference? 2. Is there a workaround for me to be able to preallocate the array? Kind regards
Arrays of functions, function signatures and template instantiation
I'm piecing together a small IRC bot as my second pet project, and next up is splitting the socket-listening/event handling into a separate thread. TL;DR: skip to the link at the bottom -- can't it be done neater? Raw IRC commands are strings whose format differs depending on the *type* of the IRC event (for lack of a better word). These event types are arbitrary short strings like "NICK", "PRIVMSG", "NOTICE", "PING", "001", etc. I'd sleep better if it were an enum, but as it is I'm parsing the type from the raw string by regex, so obviously I'm getting another string out of it. (Granted, you could cast them to that enum in a huge switch, but I'm not sure you'd gain any academic efficiency points considering the extra time spent in that switch.) After some more regex I have an Event struct with string members like .sender, .target, .type, .content and some others. Naturally, depending on what actually happened I may want to react to it. Most on-event reactions are functions to pass the Event to, like onPrivateMessage(Event evt) -- but sometimes I want to know the impending server response of a command I just sent. As an example, when you connect to a server, the first things you send are user details (full name etc) and a nickname request. If what the server sends next is the welcome event "001", then all is well -- wait for the end-of-motd event "376" and then slowly start joining your channels and doing your stuff. But if it is the nickname-in-use event "433", then everything stops until you have requested an available nick. So I had in mind an event handler and a message dispatcher. The event handler would be in its own thread listening to the socket stream, and once it reads a string it would parse it into an Event, then pass it along to the message dispatcher. The dispatcher would keep a record of which threads have registered interest in receiving what events, and would send messages accordingly. The solution that springs to mind is an associative matrix/array-of-array where one of the index keys is the event type string, and the other is the thread ID (Tid). But I still want to keep onPrivateMessage(Event evt) and friends around, so in a stroke of hubris I thought it would be neat if I could find a generic solution that could work with both arrays of thread IDs *and* arrays of function pointers. I'm not sure where the 'event handler' struct would end and where the 'message dispatcher' would start though -- perhaps I'll just combine them, call it Overlord and be done with it. Or maybe ResponsibilityCreep. Much shotgun programming later and I now have two templates; MatrixWalker and FuncRunner, subject to serious renaming. (They were called Herp and Derp a few hours back.) Given a function pointer and a matrix of type Foo[Tid][string], MatrixWalker will foreach all and invoke the function on both keys (Tid, string) and the final element Foo. The function signature must match the types used, hence the FuncRunner template as an adapter. Tid needn't be Tid unless it's in the context of messaging, naturally, and in the context of messaging Foo is irrelevant and could be bool. (Keeping a single array like Tid[string] would only allow for one event registered per Tid, so Tid has to be a key unless you could somehow store multiple values per key. Even if possible [?], deregistering the right Tid from an event string key wouldn't be straightforward anymore.) Error: function expected before (), not func of type void function(string, uint)* Yay! Woe. http://dpaste.dzfl.pl/9273fb92 Can't it be done neater than this? It *does* work now, but it's incredibly hacky and I'm not satisfied with it. The whole 'passing a function pointer to a function that casts the signature and invokes it' deal makes me cringe. :> Many thanks in advance, would love any and every piece of advice you could spare. With some luck there are some easy shortcuts and I'm just too green to see them.
Error in template instantiation from D-Cookbook example
Hi, Trying to improve my CT-fu, I looked at a DSL example (chapter 9) in Adam's D-Cookbook. Although I am sure Adam's original examples would have worked, there were some errors in the example code in the book. The example also contains some code to allow you to test the functions at RT, which had an error i.e. I had to change this... writeln(parse(code)); // to aid with debugging writeln(convertToD(parse(code))); // debugging aid ..to.. writeln(parse(code)[]); // to aid with debugging writeln(convertToD(parse(code))[]); // debugging aid ..to match the actual function arguments. So that worked fine. However I could not get the CT version to work with the current version of DMD i.e. this [1]... [1] https://run.dlang.io/is/dyElXg ...fails with: onlineapp.d-mixin-36(38): Error: template argument expected following ! onlineapp.d(48): Error: template instance onlineapp.runDslCode!"5 5 + 3 - 2 * 1 + 3 /" error instantiating. I find the error message a bit lacking as to the real cause - I really cannot see where the "template argument expected following !" error is. It all looks correct to me. In addition the RT version is working correctly (after fixing the above bug), so that is not helping in identifying the error - particularly since it is failing in the only CT specific function not used/called at RT. So I am not sure how to debug this. Can somebody please put me out of my misery here? Thx!
Template instantiation fails on Linux, succeeds on Windows
Hi! The code in [1] compiles and runs flawlessly on Windows, but not on Linux (neither run.dlang nor Travis docker image). Any idea what can be done? errors: Error: undefined identifier __va_list_tag onlineapp.d(282): Error: template instance `onlineapp.SetFactory!byte` error instantiating Error: undefined identifier __va_list_tag onlineapp.d(288): Error: template instance `onlineapp.SetFactory!(Count)` error instantiating Error: undefined identifier __va_list_tag onlineapp.d(290): Error: template instance `onlineapp.SetFactory!char` error instantiating SetFactory is defined on row 233, and it seems that the problem relates to the vararg opIndex. [1] https://run.dlang.io/gist/6dcbe4e82846cbeb3bf478e92a2b6e6f
Getting the template name of a template instantiation
If I have a template parameter E = S!int where struct S(T) { S x; } how can I extract the template name part `S` from E`? Something like: static assert(is(templateName!(S!int) == S)); Is this already in Phobos somewhere?
Re: Template instantiation and string vs const char[]
On Wednesday, 3 September 2014 at 05:18:42 UTC, Jason den Dulk wrote: [...] While not really answering your question, I believe the idiomatic way is to use enum here instead of string/char[]. Conjecture: strings are final but the symbol can be redirected to point to new arrays, such as results of concatenations. Concatenations create new and unique arrays upon each operation as each by definition cannot be altered. char[] can be *appended* to, technically retaining the same array and merely reallocating (potentially moving) to fit the extra content. This sounds like something the compiler should be able to work around but apparently it doesn't. Also, note that your check of (R.length) will only evaluate to false if the template is instantiated as somet!().
Re: Shared, ref, arrays, and reserve template instantiation
On Wednesday, 12 September 2018 at 23:41:16 UTC, James Blachly wrote: When I add the "shared" attribute to an array, I am no longer able to call reserve because the template won't instantiate: Error: template object.reserve cannot deduce function from argument types !()(shared(int[]), int), candidates are: /dlang/dmd/linux/bin64/../../src/druntime/import/object.d(4091): object.reserve(T)(ref T[] arr, size_t newcapacity) 1. Shared modifies the type, so the template does not match. Even casting does not seem to work however. Is there something about shared that makes it unable to be taken by reference? 2. Is there a workaround for me to be able to preallocate the array? Kind regards I'm guessing you tried something like: shared char[] x; // Doesn't work; it casts the result of x.reserve cast(char[])x.reserve(100); // Doesn't work; (cast(char[])x) is not an lvalue, so it can't be ref (cast(char[])x).reserve(100); Arrays are passed and stored like pointers, and `reserve` modifies the array, which is why the thing needs to be ref. Anyway, it works like this: // Cast and store in a variable so it can be ref auto b = cast(char[]) x; // Okay, reallocates b (changes b.ptr), doesn't change x b.reserve(100); // Copy changes back to the shared variable x = cast(shared) b;
Re: Shared, ref, arrays, and reserve template instantiation
On Wednesday, September 12, 2018 5:41:16 PM MDT James Blachly via Digitalmars-d-learn wrote: > When I add the "shared" attribute to an array, I am no longer > able to call reserve because the template won't instantiate: > > Error: template object.reserve cannot deduce function from > argument types !()(shared(int[]), int), candidates are: > /dlang/dmd/linux/bin64/../../src/druntime/import/object.d(4091): >object.reserve(T)(ref T[] arr, size_t newcapacity) > > 1. Shared modifies the type, so the template does not match. Even > casting does not seem to work however. Is there something about > shared that makes it unable to be taken by reference? > 2. Is there a workaround for me to be able to preallocate the > array? You can't do much of anything with shared while it's shared, which is pretty much the whole point. The way that shared needs to be used in general is essentially synchronized(mutexForSharedObj) { auto local = cast(Type)sharedObj; // do stuff with local... // ensure that no thread-local references to local / sharedObj exist // before releasing the mutex } // shared object is now essentially unusable again Doing pretty much _any_ operation on a shared object while it's shared (other than atomic operations from core.atomic) is wrong, because it's not thread-safe. The compiler prevents most operations but not as many as it should (e.g. copying is currently legal). That will likely be fixed in the future, but exactly what's going to happen to shared in all of the fine details hasn't been sorted out yet. The basics work, but not all of the details are as they should be yet. So, if you're doing anything like calling reserve or ~= on a shared array, then you need to protect it with the mutex that you have for it and cast away shared first. However, if you're just dealing with constructing the array, then what you should do is create it as thread-local and then cast it to shared after you're done setting it up and are ready to share it across threads (after which, all further operations on it should be protected by a mutex or use atomics, otherwise they're not thread-safe). - Jonathan M Davis
Re: Shared, ref, arrays, and reserve template instantiation
Great -- Thank you both. I previously found Unqual, but it looks like that needs template support so wasn't feasible, hence my question. Neia is right that I tried to cast as in the second case ( but without UFCS -- reserve( cast(int[]), N); ). As an aside, what is going on behind the scenes with the compiler when casting away a property? I did not think cast operations copied data, so was surprised that a cast value is not an lvalue. Regarding Jonathan's comments, we had definitely protected the ~= operations with Mutex, but realized we were doing lots of array appends in a hot loop, and since we have an idea of cardinality ahead of time just wanted to preallocate. Since it is all initialization before concurrent code enters the picture, we'll do what you've suggested and set it up as TL and then cast to shared. James
Re: Shared, ref, arrays, and reserve template instantiation
On Wednesday, September 12, 2018 9:42:19 PM MDT James Blachly via Digitalmars-d-learn wrote: > Neia is right that I tried to cast as in the second case ( but > without UFCS -- reserve( cast(int[]), N); ). As an aside, what > is going on behind the scenes with the compiler when casting away > a property? I did not think cast operations copied data, so was > surprised that a cast value is not an lvalue. Well, you basically get a temporary variable when you cast an object, and those are rvalues. And while casting with regards to type qualifiers such as const or shared, you're not actually changing the data, plenty of other casts do - e.g. float and long don't even have the same size, but you can cast from one to the other. So, even in principle, only some casts could result in lvalues even if we wanted them to. - Jonathan M Davis
function(pointer) as template argument, explicit template instantiation
```dptr.d class R { } void foo (R r) { } alias fn = void function (R); void lyr (fn F) (R r) { } immutable fn foo_ptr = &foo; // line 14 pragma (msg, typeof (foo_ptr)); auto ptr = lyr!(foo_ptr);// line 17 ``` dmd reports: ``` immutable(void function(R)) dptr.d(14): Error: expression `& foo` is not a valid template value argument ``` If I comment out line 17 the code compiles. I want to put the explicitly instantiated function template into an immutable AA. How can that be phrased such that dmd compiles it?
Unique IDs for each template instantiation at compile-time?
I was wondering if it was possible to generate unique(in order) IDs for each template instantiation of a class at compile-time. A short example of what I'm trying to do: static int counter = 0; class A(T) { enum id = counter++; } class B : A!B { } Ofcourse, this doesn't compile because the "counter" variable can't be read at compile-time.
assertion failure with template instantiation of forward reference class
When trying to compile this code: import std.stdio; class A; class B(T) : T { } void main() { writeln(typeid(B!A)); } I get this error: Assertion failure: '!scope' on line 358 in file 'toobj.c'. Shouldn't it be more like: Error: class main.A unable to resolve forward reference in definition Looks like a bug?
Re: Arrays of functions, function signatures and template instantiation
On Monday, 29 April 2013 at 23:49:18 UTC, JR wrote: [...] http://dpaste.dzfl.pl/9273fb92 Can't it be done neater than this? It *does* work now, but it's incredibly hacky and I'm not satisfied with it. The whole 'passing a function pointer to a function that casts the signature and invokes it' deal makes me cringe. :> To get rid of the cast: 13c13 < void applyFunc(F* func, E[I][T] matrix) { --- void applyFunc(F func, E[I][T] matrix) { 16c16 < func(major, minor, &element); --- func(major, minor, element); 29,30c29,30 < void run(T major, I minor, F* func) { < (cast(void function(T,I))*func)(major, minor); --- void run(T major, I minor, F func) { func(major, minor); 52c52 < alias MatrixWalker!(typeof(runner),typeof(funcyMatrix)).applyFunc apply; --- alias MatrixWalker!(typeof(&runner),typeof(funcyMatrix)).applyFunc apply;
Re: Arrays of functions, function signatures and template instantiation
On Tuesday, 30 April 2013 at 02:38:27 UTC, anonymous wrote: To get rid of the cast: [...] Instantiating the template with a function parameter causes a compilation error when actually calling the function; -- asdf.d:13: Error: variable asdf.MatrixWalker!(@system void(string major, uint minor, void function(string, uint) func), void function(string, uint)[uint][string]).applyFunc.func cannot be declared to be a function asdf.d:16: Error: function expected before (), not func of type _error_ -- I have a vague feeling I had it working like that at one point but I cannot recall with any degree of certainty.