mixin bug?
template F1(T) { void bar() { writeln("Bar0"); } } template F2(T) { mixin F1!T; void foo() { bar(); } } template F3(T) { mixin F2!T; void bar() { writeln("Bar1"); } // <- This bar should be used for F2's foo! } struct F4(T) { mixin F3!T; } (Or on can turn F3 in to a struct directly) Then f3.foo() calls bar from F0, not F3's bar! This seems like a big bug! One expects the same behavior of mixins regardless of mixin nesting. While you could argue that foo, when declared, is calling F0's bar, this is not consistent with the view that mixin templates only adds what is not there. I don't like the idea that calls are resolved first come first serve as it means one can't extend templates in a natural logical way.
Re: Template parameters that don't affect template type
On Thursday, 11 August 2016 at 18:11:30 UTC, Engine Machine wrote: I have the need, in some cases, to pass static information to a template class but don't want it to affect its type. import std.algorithm, core.stdc.stdlib; struct X(int defaultSize = 100) { int Size; int* p; void foo(int size) { Size = max(size, defaultSize); p = cast(int*)malloc(Size); } } If I do X!100 x; X!100 y; X!50 z; then I can do x = y; but not x = z; but of course D things these are completely different types. The type it self does not depend on the default size. While one could argue that it can be unsafe, in the my context, it is not. Is there any way to get D to understand I want do not want a template parameter to be part of the type comparison? I use several parameters to pass info to the type that does not change affect the type itself. It prevents the "same type" from being used with "itself". another example: struct s(T1, T2) { T1; } then s!(int, double) and s!(int, float) should really be the same type! The fact that T2 is not used is important! I guess D just can't handle it though? Another good example is if something like template X(bool ClearMemory = false) { } ClearMemory would clearly not affect the type if it just clears memory that is malloc'ed, yet D would treat treat X!true from X!false.
Template parameters that don't affect template type
I have the need, in some cases, to pass static information to a template class but don't want it to affect its type. import std.algorithm, core.stdc.stdlib; struct X(int defaultSize = 100) { int Size; int* p; void foo(int size) { Size = max(size, defaultSize); p = cast(int*)malloc(Size); } } If I do X!100 x; X!100 y; X!50 z; then I can do x = y; but not x = z; but of course D things these are completely different types. The type it self does not depend on the default size. While one could argue that it can be unsafe, in the my context, it is not. Is there any way to get D to understand I want do not want a template parameter to be part of the type comparison? I use several parameters to pass info to the type that does not change affect the type itself. It prevents the "same type" from being used with "itself". another example: struct s(T1, T2) { T1; } then s!(int, double) and s!(int, float) should really be the same type! The fact that T2 is not used is important! I guess D just can't handle it though?
Re: Template parameters that don't affect template type
On Thursday, 11 August 2016 at 19:28:47 UTC, Lodovico Giaretta wrote: On Thursday, 11 August 2016 at 18:11:30 UTC, Engine Machine wrote: [...] If, in your case, it is possible to use one type as the other, then specify it. I mean, implement a templated opAssign that allows you to assign values of one instantiation to values of another. While doing so, remember that this will not change the behaviour of the assigned-to variable, but will only transfer the runtime state from one variable to the other. struct S(T1, T2) { T1 t; void opAssign(T)(auto ref S!(T1, T) other) { t = other.t; } } unittest { S!(int, float) x(1); S!(int, char) y(3); x = y; assert(x.t == 3);// the value of x is changed static assert(is(typeof(x) == S!(int, float))) // the type of x isn't changed } Ok, well, my point is that in some cases, the OpAssign is trivially since everything is copied. I guess being explicit is not a bad thing in this case though.
Re: Template parameters that don't affect template type
Also, what if we use a class instead of a struct? in this case they are both references to the same thing. I see a problem with reflection though, as one could get the template parameter value and it would wrong on conversion. D takes the easy way out of just preventing complex and potentially ill-defined behavior, I guess that is ultimately a good thing, even if it makes it a pain in some cases.
Re: mixin bug?
On Thursday, 11 August 2016 at 19:05:58 UTC, sldkf wrote: On Thursday, 11 August 2016 at 17:56:47 UTC, Engine Machine wrote: template F1(T) { void bar() { writeln("Bar0"); } } template F2(T) { mixin F1!T; void foo() { bar(); } } template F3(T) { mixin F2!T; void bar() { writeln("Bar1"); } // <- This bar should be used for F2's foo! } struct F4(T) { mixin F3!T; } (Or on can turn F3 in to a struct directly) Then f3.foo() calls bar from F0, not F3's bar! This seems like a big bug! One expects the same behavior of mixins regardless of mixin nesting. While you could argue that foo, when declared, is calling F0's bar, this is not consistent with the view that mixin templates only adds what is not there. I don't like the idea that calls are resolved first come first serve as it means one can't extend templates in a natural logical way. I don't think it's a bug. F3's bar() doesn't exist yet in F2. Logically F1's one is called. Yes, but when we "mixin" again, bar then does exist. I see the mixin as a sort of copy and paste. We only paste in what doesn't exist. So the first time bar gets inserted in to F2, but then that bar doesn't get inserted in to F3 because it already exists. Basically a mixin of a mixin is not logically a mixin. That makes no sense to me. A mixin is suppose to behave a certain way, but when we do a mixin of a mixin we get behavior that doesn't behave the same way as a single mixin. The language allows to alias a mixin so that a particular overload can be called. In you case you can really target F1.bar without problem: I don't want to target F1.bar, I want foo to target future bar's. It is like overloading, but for templates. If you were doing overloading, and it called the base function instead, it wouldn't be overloading, would it? °°° template F1(T){void bar() {writeln("Bar0");}} template F2(T) { mixin F1!T FF1; void foo() { FF3.bar; } } This requires F2 to know the future. It also forces it to use a specific bar. I want inheritance like logic. Which is what we get when we mixin one deep, but when we go deeper, it breaks. I think this is a bug. It seems like D is trying to resolve things only after each mixin, rather than resolving after all nested mixins are evaluated.
Re: Template parameters that don't affect template type
On Thursday, 11 August 2016 at 18:42:51 UTC, Steven Schveighoffer wrote: On 8/11/16 2:11 PM, Engine Machine wrote: I have the need, in some cases, to pass static information to a template class but don't want it to affect its type. import std.algorithm, core.stdc.stdlib; struct X(int defaultSize = 100) { int Size; int* p; void foo(int size) { Size = max(size, defaultSize); p = cast(int*)malloc(Size); } } If I do X!100 x; X!100 y; X!50 z; then I can do x = y; but not x = z; but of course D things these are completely different types. The type it self does not depend on the default size. And they should be different types. The code generated for the type is different, in this case it's important to declare these are not the same type. For example, if x = y worked, then what should x.foo(5) do? While one could argue that it can be unsafe, in the my context, it is not. Is there any way to get D to understand I want do not want a template parameter to be part of the type comparison? The type is part of the template, and the instantiations are different. So no. I use several parameters to pass info to the type that does not change affect the type itself. It prevents the "same type" from being used with "itself". Then define how the compiler can convert from one to another. Or redesign the type to specify the parameters at the right time. another example: struct s(T1, T2) { T1; } then s!(int, double) and s!(int, float) should really be the same type! The fact that T2 is not used is important! That's not how template types work. your code is shorthand for: template s(T1, T2) { struct s { T1 t1; // I assume you wanted to put a member here? } } Two different instantiations of s create two different namespaces where the structs are not the same. I don't think this proves anything. You just rewrote the template. T2 is still not used in either case and hence the type does not depend on it. Basically your logic is something like: A = 0*5 is different than B = 0*6. But both are the same, just because they look different doesn't change that. I'd suggest if you don't use a template parameter, don't declare it. If you use it in a member function only (as in your first example), declare it in the member function as a template parameter. I guess D just can't handle it though? No, it doesn't handle incorrect assumptions very well ;) -Steve You are misunderstanding what I am asking or saying. The code may be different, but one reference can store the value of another. The type itself does not depend on the parameter. X!100 x; X!50 y; 50 for y does not change anything to the outside world about y. So, for all practical purposes, we have X x; X y; in which case we can do x = y; with no problem. You are confusing the general case with the specific case. Sure, in general, it doesn't work, we know that. But not all types are dependent on their type parameter. Just because such parameters are specified does not necessarily mean they should be different types. My example is not good because the types are different. If I did something like void foo(int size) { Size = max(size, defaultSize, 100); p = cast(int*)malloc(Size); } Then it would be different. in this case X!50 and X!100 would be the same. X!101 would not.
Re: mixin bug?
On Thursday, 11 August 2016 at 21:25:20 UTC, sldkf wrote: On Thursday, 11 August 2016 at 20:27:01 UTC, Engine Machine wrote: This requires F2 to know the future. It also forces it to use a specific bar. I want inheritance like logic. You are goind to hit a wall. Template programming is not OOP. I'm not even sure that reflection would work in order to determine the most "recent" overload. Well, duh, it is not oop, but that doesn't mean it doesn't have similar abstractions, you need to read between the lines a bit more. Which is what we get when we mixin one deep, but when we go deeper, it breaks. I think this is a bug. It seems like D is trying to resolve things only after each mixin, rather than resolving after all nested mixins are evaluated. This is the only issue I see: "It seems like D is trying to...". We need to know exactly what D does: https://issues.dlang.org/show_bug.cgi?id=16376. It would be nice if D would bind the function calls lazily, so to speak, that is all I'm saying. This way we can get polymorphic/oop like behavior, if you will. template A(T) { void Bark() { writeln("Ruff Ruff"); } } template B(T) { mixin A!T; void Talk() { Bark(); } } template Duck(T) { mixin B!T; private void Bark() { writeln("Quack"); } } this is a contrived and misleading example if you take it seriously. But Duck.Talk(); should Quack. It would if D resolved Bark from Talk after the final "mixin". (In Duck, not in B). Else we are stuck with a barking duck. What it seems to do is first evaluate the template A!T, then B!T, then Duck!T. Since B!T is evaluated first and plugged in to Duck, Talk is already resolved to use A!T.Bark. Rather, If Duck!T was evaluated first, D would understand that Bark was already defined and when Talk was added, it could have it use the bark defined in duck, rather than A. This, would, of course, require a sort of Duck!T.B!T type, since B!T used inside of Duck would have a different Talk() than if it is not used in Duck. Again, maybe the compiler is just to ignorant to do this as it is complex(might require flow analysis and all that stuff or just be an ill-defined problem in general).
Re: mixin bug?
On Thursday, 11 August 2016 at 21:03:36 UTC, Ali Çehreli wrote: On 08/11/2016 01:27 PM, Engine Machine wrote: > I see the mixin as a sort of copy and paste. That's the case for string mixins. Template mixins bring a name resolution scope. My understanding of the topic: http://ddili.org/ders/d.en/mixin.html#ix_mixin.name%20space,%20mixin The spec: https://dlang.org/spec/template-mixin.html Ali "When a mixed-in name is the same as a name that is in the surrounding scope, then the name that is in the surrounding scope gets used:" Which is my point, for "2nd order or higher" mixins, this does not occur. The why I see it is that mixin template is sort of like a copy and paste, but only paste if the members do not exist already(i.e., the current behavior for "1st order" mixins. I would expect the same logic to hold for higher order mixins since a mixin of a mixin is still a mixin). I realize why D behaves the way it does, but this is limiting. It simply greedily resolves referencing members rather than lazily. If the greedy method actually has some desired characteristic, then a lazy mixin would be nice. lazy mixin T1!T;
Re: mixin bug?
On Friday, 12 August 2016 at 23:48:54 UTC, sldkf wrote: On Friday, 12 August 2016 at 23:14:23 UTC, Engine Machine wrote: On Friday, 12 August 2016 at 15:35:50 UTC, sldkf wrote: On Friday, 12 August 2016 at 02:09:21 UTC, Engine Machine wrote: On Thursday, 11 August 2016 at 21:25:20 UTC, sldkf wrote: On Thursday, 11 August 2016 at 20:27:01 UTC, Engine Machine This is not the solution to the original problem. template X(T) { int _len = 0; int Length() { return _len; } int length(this T)() { return (cast(T)this).Length(); } } template Y(T) { mixin X!T; int Length() { return 3; } } Then calling length returns 0, while calling Length returns 3. But we obviously want length to "follow" Length, yet it doesn't due to D resolving length in X before it is mixed in Y!T. No "length" returns 3. https://ideone.com/T8HjZl Really, it's there, in front of your eyes. You're right. My mistake. Thanks! Do I have to do this with every function call? Seems a bit tedious to have to add this T to every function and add this. to every call.
Re: Template parameters that don't affect template type
On Thursday, 11 August 2016 at 20:43:13 UTC, Meta wrote: On Thursday, 11 August 2016 at 18:11:30 UTC, Engine Machine wrote: [...] It can be done, but you have to be explicit and should think very carefully if this is really a good design. struct X(int defaultSize = 100) { int size; int* p; void foo(int size) { size = max(size, defaultSize); p = cast(int*)malloc(size); } X opAssign(X2: X!n, int n)(X2 other) { //Do whatever you want here } X2 changeDefaultSize(int n)() { auto newX = X!n(n, p); p = null; //Release ownership of p return newX; } } void takesX50(X!50 x) { //... } void main() { X!100 n; X!100 m; X!50 o; n = m; o = m; takesX50(n); //Error takesX50(n.changeDefaultSize!50); //Okay } Really though this problem is properly solved by runtime polymorphism. Thanks. I am using templates and in some cases use template arguments to set compile time properties, hence runtime won't work. These arguments don't affect the type itself, as far as the functionality/behavior as I use them.
Re: mixin bug?
On Friday, 12 August 2016 at 15:35:50 UTC, sldkf wrote: On Friday, 12 August 2016 at 02:09:21 UTC, Engine Machine wrote: On Thursday, 11 August 2016 at 21:25:20 UTC, sldkf wrote: On Thursday, 11 August 2016 at 20:27:01 UTC, Engine Machine issue solved using a "template this parameter": °° template Cow() { void soundImpl() { writeln("moo"); } } template Cat() { mixin AnimalSound; void soundImpl() { writeln("meaow"); } } template Duck() { mixin Cat; void soundImpl() { writeln("quack"); } } template AnimalSound() { void emittSound(this T)() { (cast(T) this).soundImpl(); } // would also work with "this.soundImpl()" } struct Animal { mixin Duck; } void main() { Animal a; a.emittSound; } °° https://dlang.org/spec/template.html#TemplateThisParameter This is not the solution to the original problem. template X(T) { int _len = 0; int Length() { return _len; } int length(this T)() { return (cast(T)this).Length(); } } template Y(T) { mixin X!T; int Length() { return 3; } } Then calling length returns 0, while calling Length returns 3. But we obviously want length to "follow" Length, yet it doesn't due to D resolving length in X before it is mixed in Y!T.
if static member then call
auto ref foo(T, Args...)(args) { static if (hasStaticMember!(T, "foo")) return T.foo!(T)(args); } Basically I want to forward the *static* call to T if possible(if foo exists in T). The main problem is actually calling T.foo as the syntax here doesn't work. I also need to be able to check to see if a method is static, since I have no object.
Re: Passing Structs to function like in C
On Friday, 12 August 2016 at 18:23:55 UTC, Cauterite wrote: Thanks colon-nazis, I'll take that into consideration ¬_¬ Be careful! They will cauterize your testicles and rape your children! Those semi-clone, I mean semi-colon-nazis are the worse kind! It's a life and death matter! After all, `proper`(by section 8.043 of the penile nazile book of the dead) use of ';' is more important than your testicles anyways, right?
Re: Passing Structs to function like in C
On Friday, 12 August 2016 at 17:53:12 UTC, ag0aep6g wrote: On 08/12/2016 07:33 PM, Cauterite wrote: Why would I not terminate a declaration with a semi-colon? Why should a declaration not end in a semi-colon just because the last token is a brace? Why should I not tell the lexer precisely where my declaration ends instead of relying on whatever other tokens floating around it not interfering? The semicolon is just noise. You're not helping the lexer at all. It goes by the braces, and doesn't see the semicolon as belonging to the function declaration. The semicolon creates another, empty declaration. Then it should error if it doesn't accept ';'. If it accepts it then it is legal. Your post is noise since it also is relatively meaningless and just takes up space. Why is it no ok for him to add a noisy ';' but it is ok for you to add noise to noise by adding a noisy post? This is accepted as well, and means the same: ;;; void main() {} ;;; Why must every thread in this forum contain more posts regarding some irrelevant tangent than posts responding to the original topic? This is a common mistake - more for structs, though, because of C syntax. So I point it out so that you can learn that there's no point to it in D, and so that others don't get the impression that it's the proper syntax. It is not a mistake... only in your mind. If it was a mistake D wouldn't allow it. Somewhere you picked up the mistake that adding a semicolon to the end of a struct is a mistake. Maybe you should unlearn that mistake? There is no point in a lot of things, but pretending that life depends on such trivial things is a much worse mistake, IMO.
Re: if static member then call
On Saturday, 13 August 2016 at 18:42:50 UTC, Cauterite wrote: On Saturday, 13 August 2016 at 18:34:43 UTC, Engine Machine wrote: static if (hasStaticMember!(T, "foo")) Here I suspect you're looking for this: __traits(isStaticFunction, __traits(getMember, T, "foo")) Thanks. It needs to be something like static if (hasMemeber!(T, "foo") && __traits(isStaticFunction, __traits(getMember, T, "foo")))
How to add nogc to delegate
void foo(@nogc void delegate()) doesn't work. But declaring an alias does, but too verbose. Surely we should be able to add the attribute directly?
Re: callback craziness
On Sunday, 7 August 2016 at 23:02:26 UTC, ag0aep6g wrote: On 08/08/2016 12:08 AM, Engine Machine wrote: On Sunday, 7 August 2016 at 20:48:29 UTC, ag0aep6g wrote: [...] Delegates don't necessarily need a GC allocation. They only need it when they need a closure. Delegates of methods don't need closures. And when you pass the delegate in a `scope` parameter, no closure is needed, either. Well, one can't pick the case the delegate is passed. When I use a delegate in the nogc context it errs. Not exactly. When you do something that requires a closure, it errors out. As I said, a delegate doesn't always require the allocation of a closure. This works just fine, and it uses a delegate parameter: @nogc void foo(void delegate(int x) @nogc f) {} void main() @nogc { foo((int x) {}); struct S { int y; void f(int x) @nogc { this.y = x; } } S s; foo(); } But this doesn't compile, because the delegate here would need a closure: @nogc void foo(void delegate(int x) @nogc f) {} void main() @nogc { int y; foo((int x) { y = x; }); } Also note that it's main's @nogc that makes this fail, not foo's or the parameter's. Remove main's @nogc and it works. [...] You're missing an argument there. The second parameter of foo is `args` which is `string` here. This call works: foo!string((int x, string s) { }, "", 1); Yeah, that was just a typeo obvious. That's not the reason it fails. No. It's exactly the reason it fails. Add a string argument and it works: alias callback(Args) = @nogc void function(int x, Args); @nogc void foo(Args...)(callback!Args f, auto ref Args args, int extra = 0) {} void main() @nogc { foo!string((int x, string s) { }, "", 1); } [...] One thing you need to fix: The `callback` template needs a template sequence parameter (i.e. `Args...`). Otherwise it takes exactly one type. I did try that first and it didn't work. it works without ..., and I figured that it is a template parameter and can also represent a sequence? No, without `...`, the template parameter only accepts exactly one type, not more than one, not none. So, what about passing in the lambda verses the temp variable? I tried the ... same problem as I said. f!()(...) doesn't work. Everything works find as long as I pass more than one variable. My code is as follows and I cannot get 0 parameters working nor passing the function in directly. These were my original questions to begin with and haven't been answered. Here is the code I am using. alias callback(Args...) = @nogc void function(string, int, Args); @nogc public void foo(Args...)(callback!Args c, Args args, int x) { } foo((string s, int i) { }, 1); does not work nor does foo!()((string s, int i) { }, 1); Ultimately it would also be nice if the template parameters were deduced automatically instead of having to specify them. The compiler should be able to figure out the types supplied parameters. e.g., foo((string s, int i, T x) { }, someT, 1); instead of foo!(T)((string s, int i, T x) { }, someT, 1); should it not?
Cannot distinguish between template function wtih 0 args and 1 arg
This really makes no sense Error: template Mem cannot deduce function from argument types !(cast(eException)1280L, "main.d", 38u, "main.WinMain")(int), candidates are: Mem(T, B = eX, string file = __FILE__, uint line = __LINE__, string func = __FUNCTION__)(size_t bytes) Mem(T, B = eX, string file = __FILE__, uint line = __LINE__, string func = __FUNCTION__)() Shouldn't these template functions be completely distinguished? I tried to calling it with and without a value but same error. It is the only error. This only occurs when I call it with the non-default template values: I call it simply like Mem!(T, B, file, line, func)(34). It seems if the template parameters match, that the compiler doesn't test the arguments. Mem!T(34) works fine.
Re: callback craziness
On Sunday, 7 August 2016 at 20:48:29 UTC, ag0aep6g wrote: On 08/07/2016 10:01 PM, Engine Machine wrote: @nogc void foo(void delegate(int x) @nogc f); fails with the @nogc. Compiles just fine for me. 2nd, I cannot use a delegate because of the @nogc context, Delegates don't necessarily need a GC allocation. They only need it when they need a closure. Delegates of methods don't need closures. And when you pass the delegate in a `scope` parameter, no closure is needed, either. Well, one can't pick the case the delegate is passed. When I use a delegate in the nogc context it errs. [...] So, to get around these problems, I have to do something like this: alias callback(Args) = @nogc void function(int x, Args); @nogc void foo(Args...)(callback!Args f, auto ref Args args, int extra = 0) The problem with this is that I can't seem to add f inline: foo!string((int x, string s) { }, 1); this fails with template mismatch. You're missing an argument there. The second parameter of foo is `args` which is `string` here. This call works: foo!string((int x, string s) { }, "", 1); Yeah, that was just a typeo obvious. That's not the reason it fails. But if I define the lambda outside it works: auto f = (int x, string s) { }; foo!string(f, 1); Doesn't work for me. Still missing the string argument. Yes, same typo. The problem with this is that when I want to pass no arguments, auto f = (int x) { }; foo(f, 1); fails. It seems that Args... requires at least one argument to match the template? This may be a bug? One thing you need to fix: The `callback` template needs a template sequence parameter (i.e. `Args...`). Otherwise it takes exactly one type. I did try that first and it didn't work. it works without ..., and I figured that it is a template parameter and can also represent a sequence? But I only tried with one argument so it worked. I added ... but same problems. That doesn't make it work, though. You also need to add empty template instantiation parentheses (i.e. `foo!()`), and you need to remove `auto ref` from the `args` parameter. No idea why it doesn't work with `auto ref`. At least that part looks like a bug to me. Yeah, so, this is typically what happens. One bug makes me change my tail for two hours ;/
callback craziness
I use callbacks a lot and have trouble with D in a nogc context. First, I cannot declare the parameters with a nogc or I get a compile time error. @nogc void foo(void delegate(int x) @nogc f); fails with the @nogc. 2nd, I cannot use a delegate because of the @nogc context, @nogc void foo(void function(int x) f); Works, but f then cannot access the context. So, to get around these problems, I have to do something like this: alias callback(Args) = @nogc void function(int x, Args); @nogc void foo(Args...)(callback!Args f, auto ref Args args, int extra = 0) The problem with this is that I can't seem to add f inline: foo!string((int x, string s) { }, 1); this fails with template mismatch. But if I define the lambda outside it works: auto f = (int x, string s) { }; foo!string(f, 1); The problem with this is that when I want to pass no arguments, auto f = (int x) { }; foo(f, 1); fails. It seems that Args... requires at least one argument to match the template? This may be a bug? alias callback(Args) = @nogc void function(string, int, Args); @nogc public void foo(Args...)(callback!Args c, auto ref Args args, int extra = 0) { ... } auto f = (string s, int l) @nogc { printf("%s\n", s.ptr); }; foo(f, 1); or auto f = (string s, int l, string x) @nogc { printf("%s\n", x.ptr); }; foo!string(f, "Test string", 1); which is the case that work sin mine code. But I don't always want to have to pass stuff. Any ideas? I realize the code is messy. You'll have to read between the lines. So, the two problems I have is that I would like to be able to add a @nogc callback inline and to be able to pass no arguments.
I thought mixins didn't override?
I try to use a mixin template and redefine some behaviors but D includes both and then I get ambiguity. I was sure I read somewhere that when one uses mixin template it won't include what is already there? mixin template X { void foo() { } } struct s { mixin template void foo() { } } I was pretty sure I read somewhere that D would not include the foo from the template since it already exists.
Sequence separation
alias x = AliasSeq!(a, b, AliasSeq!(c, d)); results in a flat sequence. I would like to be able to keep them separate so I can have sub sequences. x.length == 4;
Re: Template type reduction
On Tuesday, 16 August 2016 at 17:39:14 UTC, Lodovico Giaretta wrote: On Monday, 15 August 2016 at 19:31:14 UTC, Engine Machine wrote: Suppose I have a templated type like struct S(T) { int x; static if (T is Y) int y; } I would like to be able to create a reference to S(T) for any T, struct Q { S!* s; // Can hold any type of S. } and be able to access s.x, since it is common to all S. Can D do anything like this? It is sort of like runtime inheritance, but at the compile time level. I do not want to have to cast to S!T every time just to access x, e.g., struct Q { Object s; } which is too general as s can be things that are not of type S!*. Is this possible? I don't know if this is exactly what you want: = import std.traits: hasMember; struct Q(T) if (hasMember!(T, "x")) { T s; @property auto x() { return s.x; } } auto makeQ(T)(auto ref T val) { return Q!T(val); } auto s = myTypeWithFieldX(); auto q = makeQ(s); assert(q.x == s.x); = `Q` can store any type with an `x` field and gives access to it. The auxiliary function `makeQ` acts as a constructor for `Q` with template parameter deduction. The only problem is Q is still defined by T. Your makeQ then requires the type implicitly, which I don't necessarily have. You've simply added complexity to the problem but the issue is still there. I realize now that D simply cannot do what I ask directly because It's type parameters are part of the type. It can't be told that in some cases they are not. Any use of the parameters, as I am using them, will result in this issue. I'm now trying a different method which builds the based types using partial oop and partial CT code. The CT code is only for performance and convenience anyways.
Re: Heterogeneous CT array like structure
On Tuesday, 16 August 2016 at 15:56:18 UTC, Adam D. Ruppe wrote: On Tuesday, 16 August 2016 at 15:40:19 UTC, Engine Machine wrote: How can I actually store this data for runtime use that doesn't require the GC? The indexing set is fixed at compile time. Just create an ordinary struct... You could even create one from code flow at compile time. string magic(string structName) { import std.conv; struct Value { string name; string type; string value; } struct Magic { Value[] values; void opDispatch(string name, T)(T value) { values ~= Value(name, T.stringof, to!string(value)); } string toCodeString() { string s; s ~= "struct " ~ structName ~ " {\n"; foreach(value; values) { s ~= "\t"; s ~= value.type; s ~= " "; s ~= value.name; s ~= " = "; if(value.type == "string") s ~= "`" ~ to!string(value.value) ~ "`"; else s ~= to!string(value.value); s ~= ";\n"; } s ~= "}"; return s; } } Magic magic; magic.a = 10; magic.b = "cool"; return magic.toCodeString(); } pragma( msg, magic("MagicStruct")); mixin(magic("MagicStruct")); void main() { MagicStruct ms; import std.stdio; writeln(ms.a); writeln(ms.b); } This seems like a long winded way of just creating a struct in the first place, which might bet the simplest way anyways. What I am trying to do is create preferences for my app: if (Preferences.EnableHQ) ... But I don't want to have to define EnableHQ at the point of use! This may be impossible since D doesn't know the type, although I could do if (Preferences.EnableHQ!bool) or something like that. Anyways, I want to just be able to create preferences on the fly in the code when I feel like I need one without having to do anything else like go edit a struct, etc. Then, later, I can go deal with that. What I was thinking I could do is, is use opDispatch, write any calls to it to a file. Then use import to import that file in to the struct. It would be the data(like static bool EnableHQ = false). Eventually opDispatch should never be called, which can easily be checked and I can import the file by handle and make changes if necessary. The problem with this method is it requires multiple passes and not extensible. Have any better ideas? All this is just trying to be lazy. I could just edit a struct and add the variables as I create them.
Re: Template type reduction
On Monday, 15 August 2016 at 19:40:37 UTC, Steven Schveighoffer wrote: On 8/15/16 3:31 PM, Engine Machine wrote: Suppose I have a templated type like struct S(T) { int x; static if (T is Y) int y; } I would like to be able to create a reference to S(T) for any T, struct Q { S!* s; // Can hold any type of S. } and be able to access s.x, since it is common to all S. Can D do anything like this? It is sort of like runtime inheritance, but at the compile time level. I don't think so. You'd have to cast, as the compiler doesn't have any understanding that all S instantiations will have an x member. This is a problem. How can I cast to something I don't know? I do not want to have to cast to S!T every time just to access x, e.g., struct Q { Object s; } which is too general as s can be things that are not of type S!*. This seems odd. You will lose the type information for s if you were to succeed. Might as well just store an int. Seems like what you want is a variant or some other kind of tagged union. No, what I want is a type that is the intersection of all the types it can be. The problem is I cannot cast because the type is complex and I don't know the exact signature, but I do know that it has a basic type embedded in it. enum Types { Int, Word, Complex } struct MyType(string name, Types type, Args...) { string Name = name; Types Type = type; static if (type == Int) int val; static if (type == word) ushort val; static if (type == Complex) { ... }; } So, how can I get val? I know if it is an int or a word, val exists. But I can't specify the name or type at runtime to get at the innards of the type. Object o = MyType!("test", Types.Int); Useless! I can never retrieve anything from o. I can't cast it back. Yet I know that o has a name and a type and possibly a val if I know the type... and I know all this at compile time. Yet D doesn't seem to allow me to use this information. I know one will say use either oop or constructors, but neither of these are appropriate(although constructors are close). What I need is a type constructor, which bridges the gap. This is how I am using the data above, to construct the object, but D treats it as part of the type, which I don't what. I guess I will have to use string mixins to construct the types properly ;/ What a pain in the ass ;/
Template type reduction
Suppose I have a templated type like struct S(T) { int x; static if (T is Y) int y; } I would like to be able to create a reference to S(T) for any T, struct Q { S!* s; // Can hold any type of S. } and be able to access s.x, since it is common to all S. Can D do anything like this? It is sort of like runtime inheritance, but at the compile time level. I do not want to have to cast to S!T every time just to access x, e.g., struct Q { Object s; } which is too general as s can be things that are not of type S!*. Is this possible?
Re: Sequence separation
On Wednesday, 17 August 2016 at 08:37:32 UTC, Lodovico Giaretta wrote: On Tuesday, 16 August 2016 at 23:18:28 UTC, Adam D. Ruppe wrote: On Tuesday, 16 August 2016 at 19:17:27 UTC, Engine Machine wrote: alias x = AliasSeq!(a, b, AliasSeq!(c, d)); results in a flat sequence. I would like to be able to keep them separate so I can have sub sequences. wrap them in a struct. You mean something like: struct MySequence(Args...) { enum length = Args.length; alias args = Args; } alias x = MySequence!(a, b, MySequence!(c, d)); static assert(x.length == 3) static assert(x.args[2].length == 2); Thanks, basically works. How can I test, though, if a argument uses a MySequence? I can't do if (Args[0] == MySequence) because MySequence is templated. While I could test for a length, that doesn't work because some types have a length. I could add another enum to MySequence, but again, not safe. I could do some string tests, but that doesn't work. in your exmaple, if (x.args[2] == MySequence) ?? I simply need to differentiate between a parameter/arg being a MySequence and not.
Static CT Factory
I have a template that is suppose to create a type based on a template parameter static if (T == "int") { auto x = New!int(); } else static if (T == "double") { auto x = New!double(); } x = 1.234; This is just an example, I use custom types. The static if's prevent x's scope from being after them, even though it should work perfectly fine. I can't declare x before because I don't know the type. The point is that I don't want to have to put x = 1.234; in each static if block when I should be able to do it perfectly fine afterwards. My types that I'm creating all have a name field and I want to set it once after the object is created. Luckily, all of them inherit from the same type and I can declare that before the static if block, but in general, that won't work. I feel that in this case I feel that the scope of the static if should allow things to escape since, well, they are static if's. It would be similar to #ifdef. I realize that D doesn't work this way, I'm asking for a nicer solution than having to duplicate the same code(x = 1.234 in this example) or having use a base class.
Re: Rebind template(bug?)
On Sunday, 21 August 2016 at 06:28:25 UTC, Jack Applegame wrote: On Sunday, 21 August 2016 at 00:06:07 UTC, Engine Machine wrote: On Saturday, 20 August 2016 at 22:21:00 UTC, ag0aep6g wrote: On 08/21/2016 12:11 AM, Engine Machine wrote: Is there a way to rebind the arguments of a template? template foo(X) { // X is like A!(a,b,c) Y = Rebind!(X,d,e,f); // Y is like A!(d,e,f); } foo(A!(a,b,c)); ? template Rebind(alias instance, newArgs...) { import std.traits: TemplateOf; alias tmpl = TemplateOf!instance; alias Rebind = tmpl!newArgs; } This doesn't work because the rebound type is of type tmpl and not the original e.g., Rebind!(T!b, a) is tmpl!a not T!a. You are wrong. tmpl is just alias of template T. So tmpl!a and T!a are the same type. alias X = T!(int, short, char); alias Y = Rebind!(X, short, char, int); static assert(is(Y == T!(short, char, int))); // passes I know you like to play the right or wrong game, but did you ever learn that a single example does not prove the truth of something? How about something more complex? import std.stdio; import std.meta, std.traits; class base { } template Rebind(alias instance, newArgs...) { import std.traits: TemplateOf; alias tmpl = TemplateOf!instance; static if (newArgs.length > 0) alias Rebind = tmpl!newArgs; else alias Rebind = base; } template EraseLast(A...) { static if (A.length > 0) alias EraseLast = Erase!(A[$-1], A); else alias EraseLast = base; } class T(A...) : Rebind!(T!A, EraseLast!A) { int x; static if (A.length > 0 && A[0] == "Animal") { int y; static if (A.length > 1 && A[1] == "Dog") { int z; static if (A.length > 2 && A[2] == "Pug") int s; } } } pragma(msg, is(T!("Animal", "Dog", "Pug") : T!("Animal", "Dog"))); pragma(msg, is(T!("Animal", "Dog", "Pug") : T!("Animal"))); pragma(msg, is(T!("Animal", "Dog", "Pug") : base)); pragma(msg, is(T!("Animal", "Dog") : T!("Animal"))); pragma(msg, is(T!("Animal", "Dog") : base)); pragma(msg, is(T!("Animal") : base)); // all true void main() { auto t = new T!("Animal", "Dog", "Pug")(); T!("Animal", "Dog") q = t; //T!("Animal", "Dog", "Pug") q = t; works but then q is not the super of t t.x = 3; t.y = 4; t.z = 6; t.s = 123; q.y = 1; writeln(t, ", ", typeof(t).stringof); writeln(q, ", ", typeof(q).stringof); writeln("---"); writeln(t.x); writeln(t.y); writeln(t.z); writeln(t.s); writeln("---"); writeln(q.x); writeln(q.y); writeln(q.z); writeln("---"); writeln(t.y); writeln("---"); writeln(); writeln(); } Since the pragma's are true, it is obvious that the inheritance should work chain works. Yet q is not a reference to t as it should be, why is this? If aliases were truly aliases as you think(your generic response) then it should work because rebind and erase only use aliases.
Re: Rebind template(bug?)
On Sunday, 21 August 2016 at 19:42:08 UTC, Lodovico Giaretta wrote: On Sunday, 21 August 2016 at 19:29:26 UTC, Engine Machine wrote: [...] The problem of this code has nothing to do with aliases. They work correctly. The problem is variable shadowing. In the following code, Child has two x variables, one of which is only accessible from a Parent reference, the other only from a Child reference. class Parent { int x; } class Child: Parent { int x; // this shadows Parent.x int y; } void main() { Child child = new Child(); Parent parent = child; child.x = child.y = 3; parent.x = 2; assert(child.x == 3); assert((cast(Child)parent).x == 3); assert((cast(Parent)child).x == 2); assert(parent is child); // same object (remember that a class is already a pointer); assert( != ); // but there are two different pointers on the stack (pointing to the same object) } You're right. I didn't realize that variables could be shadowed in classes. Seems dangerous. D doesn't allow shadowing in a normal context and gives an error so I don't know why it wouldn't do that in classes. (since it wasn't giving an error I thought it wasn't shadowing)
Re: Rebind template(bug?)
On Sunday, 21 August 2016 at 21:11:37 UTC, ag0aep6g wrote: On 08/21/2016 09:29 PM, Engine Machine wrote: I know you like to play the right or wrong game, but did you ever learn that a single example does not prove the truth of something? But you can show in a single example that something doesn't work. You tried to do that, and you did it with a simple example, which is always appreciated. But apparently, you were wrong. Happens to the best. And when the compiler prints "tmpl!a" that's indeed a little misleading. You being wrong there doesn't mean that the Rebind template as I posted it works correctly, of course. But Jack didn't claim that. He just said that your example for how it doesn't work is wrong. And as far as I see, Rebind does work as expected. But I wouldn't be surprised if there is some edge case where things fall apart. Also, if you're looking for help or civil discussion, I suggest you try a less antagonistic approach. Things like "I know you like to [play games]" and "did you ever learn [whatever]" do not set the tone for that. How about something more complex? import std.stdio; import std.meta, std.traits; class base { } Style nitpick: Class names in PascalCase, please. template Rebind(alias instance, newArgs...) { import std.traits: TemplateOf; alias tmpl = TemplateOf!instance; static if (newArgs.length > 0) alias Rebind = tmpl!newArgs; else alias Rebind = base; } template EraseLast(A...) { static if (A.length > 0) alias EraseLast = Erase!(A[$-1], A); This line can be simplified: alias EraseLast = A[0 .. $ - 1]; else alias EraseLast = base; This is quite surprising for a template that's called "EraseLast". I renamed it to "EraseLastOrBase" for myself when looking at this. } class T(A...) : Rebind!(T!A, EraseLast!A) The core idea of Rebind isn't needed here, is it? You've got T, so you can just pass it directly. No need to extract it from T!A. So, instead of using some form of Rebind, you can use a simpler template: /* Instantiates tmpl with args, or if no args given, returns base. */ template InstantiateOrBase(alias tmpl, args ...) { static if (args.length == 0) alias InstantiateOrBase = base; else alias InstantiateOrBase = tmpl!args; } class T(A...) : InstantiateOrBase!(T, EraseLast!A) { int x; Note that this means that every instantiation of T brings its own x. That is, T!foo declares an x, and T!(foo, bar) which inherits from T!foo adds another x. The same happens with y, z, and s, of course. static if (A.length > 0 && A[0] == "Animal") { int y; static if (A.length > 1 && A[1] == "Dog") { int z; static if (A.length > 2 && A[2] == "Pug") int s; } } } pragma(msg, is(T!("Animal", "Dog", "Pug") : T!("Animal", "Dog"))); pragma(msg, is(T!("Animal", "Dog", "Pug") : T!("Animal"))); pragma(msg, is(T!("Animal", "Dog", "Pug") : base)); pragma(msg, is(T!("Animal", "Dog") : T!("Animal"))); pragma(msg, is(T!("Animal", "Dog") : base)); pragma(msg, is(T!("Animal") : base)); Asserts are great to show that something holds. When someone like me makes changes to your code in order to understand it, the complier throws a nice loud error in their face when they mess up. So I changed these to static asserts for myself. // all true void main() { auto t = new T!("Animal", "Dog", "Pug")(); T!("Animal", "Dog") q = t; //T!("Animal", "Dog", "Pug") q = t; works but then q is not the super of t t.x = 3; t.y = 4; t.z = 6; t.s = 123; q.y = 1; writeln(t, ", ", typeof(t).stringof); writeln(q, ", ", typeof(q).stringof); writeln("---"); writeln(t.x); writeln(t.y); writeln(t.z); writeln(t.s); writeln("---"); writeln(q.x); writeln(q.y); writeln(q.z); writeln("---"); writeln(t.y); writeln("---"); writeln(); writeln(); } Since the pragma's are true, it is obvious that the inheritance should work chain works. Yet q is not a reference to t as it should be, why is this? It would help a lot if you would point out what parts of the output are surprising to you. If you let the reader figure it out themselves, chances are 1) people are not going to bother, and 2) if they do bother, they might miss your point. Labeling the output also helps. By that I mean, if you write `writeln("t.x: ", t.x);`, the output can be read much more easily. I also think that you could have made your point with less output, which would again make it easier to follow. That is, just looking t.x/q.x would have been enough, no? I guess you expect q.x and friends to be the same as t.x and friends. And since you put it there, you may also expect to be the same as About the members being different: That's because every instantiation brings its own x/y/z, as mentioned above. Lodovico has
Re: Rebind template(bug?)
On Monday, 22 August 2016 at 00:22:48 UTC, ag0aep6g wrote: On 08/22/2016 12:06 AM, Engine Machine wrote: T!()'s "data" is specified in the class just like all the other derivations. I don't want to have to specify an external base class as in your InstaniateOrBase. Why? Because!!! (There should be no need to, and if one goes this route of creating classes, it should be all or nothing, else there is no real benefit) You make it sound like I came up with the external base class, but I just took that from your code. No, what I meant was I don't want a base. I only added it in my code so it would compile/do what I want. [...] It seems that when one uses `class T(A...) : X`, one can't, for some X, not have inheritance. The compiler expects X to be something inheritable from no matter what. I didn't know it, but your code shows that X can also be an empty compile time list (Seq). I have no idea if this is in the spec, or if it just happens to work with dmd. If it's valid D, you just need a template that goes from T and A to T!(A[0 .. $ - 1]), or if A is already empty, to the empty Seq. Like so: template InstantiateOrEmptySeq(alias tmpl, args...) { alias Seq(T...)=T; static if (args.length > 0) alias InstantiateOrEmptySeq = tmpl!(args[0 .. $ - 1]); else alias InstantiateOrEmptySeq = Seq!(); } class T(A...) : InstantiateOrEmptySeq!(T, A) { ... } Yes! I though I tried that from Timon's original solution. The following code works and does what I want! template InstantiateOrEmptySeq(alias tmpl, args...) { alias Seq(T...)=T; static if (args.length > 0) alias InstantiateOrEmptySeq = tmpl!(args[0 .. $-1]); else alias InstantiateOrEmptySeq = Seq!(); } class T(A...) : InstantiateOrEmptySeq!(T, A) { static if (A.length == 0) { // Base class int x; } else static if (A[$-1] == "Animal") { int y; } else static if (A[$-1] == "Dog") { int z; } else static if (A[$-1] == "Pug") { int s; } else static assert(A[$-1]~" not a defined class of "~this.stringof); } The only down side is that the static if's are flat. They don't show the relationship between, say, Dog an Animal, that a nested set of static if's would show, but I think this is not possible due to the recursion and shadowing(I imagine one could test if the variables exist but that is messy). Anyways, Thanks for the help. I think this is just Timons answer anyways. What the original confusion was, was the shadowing, which I thought would not happen(or at least expected an error), Lodovico solved that.
Re: Static CT Factory
On Friday, 19 August 2016 at 01:25:10 UTC, Anonymouse wrote: On Friday, 19 August 2016 at 01:10:42 UTC, Engine Machine wrote: I have a template that is suppose to create a type based on a template parameter static if (T == "int") { auto x = New!int(); } else static if (T == "double") { auto x = New!double(); } x = 1.234; This is just an example, I use custom types. The static if's prevent x's scope from being after them, even though it should work perfectly fine. I can't declare x before because I don't know the type. I'm not sure I understand. static if shouldn't introduce a new scope that way. https://dpaste.dzfl.pl/7b63a6e52309 Mind that x might be a pointer. Ok, well, I guess the error comes from something else.
Re: Static CT Factory
On Friday, 19 August 2016 at 02:54:48 UTC, Basile B. wrote: On Friday, 19 August 2016 at 01:53:22 UTC, Engine Machine wrote: On Friday, 19 August 2016 at 01:25:10 UTC, Anonymouse wrote: On Friday, 19 August 2016 at 01:10:42 UTC, Engine Machine x = 1.234; Ok, well, I guess the error comes from something else. *x = 1.234 for when T verifies is(T == int*) produces an error. You can put an aditional argument in the function header: void foo(T)(auto ref T t = T.init) { static if (is(T == int)) auto x = new Thing!int; else static if (is(T == double)) auto x = new Thing!double; else static assert(false, "incorrect type"); *x = t; } It was because I had a added a new type that I didn't account for in the static if chain ;/ The static assert is sort of required. We sort of need a static switch with required default so forgetting this stuff doesn't break later on(in strange ways) when new types are added.
Re: Static CT Factory
On Friday, 19 August 2016 at 01:18:28 UTC, Adam D. Ruppe wrote: On Friday, 19 August 2016 at 01:10:42 UTC, Engine Machine wrote: I feel that in this case I feel that the scope of the static if should allow things to escape since, well, they are static if's. They do. What, exactly, did you do and what, exactly did you see as the error? I get undefined identifier, but when create the variable outside it works. I used Anonymouse code and it works so I guess the issue stems from something else. My code is more complex and the stuff is in a foreach. I don't know why it isn't working since the simplified code is nearly identical. Maybe a branch wasn't being taken, I thought I covered them all.
Heterogeneous CT array like structure
struct Storage { // Getter static auto ref opDispatch(string name)() { } // Setter static auto ref opDispatch(string name, T)(T val) { } } auto y = Storage.Data; Storage.Data = "x"; Storage.Foo = 3; How can I actually store this data for runtime use that doesn't require the GC? The indexing set is fixed at compile time. In fact, it could come from an enum(my first thought). The values for each index can have a different type, though, and I'd like them to be the proper types(no casting or variant). Is there a simple way to add to Storage at compile time? e.g., add static string Data = "x"; static int Foo = 3; The assignments are for default values, they will only occur once in program execution, what is important is the getter, which will create the data if it doesn't exist and set it to some default value initially if it needs to.
CT Inheritence structures
I am trying to get Timon Gehr's code working, with some modifications: public template TypeParent(P) { import std.traits; alias T = TemplateArgsOf!P; alias Seq(T...) = T; static if (T.length == 0 || is(typeof(T[0]) == typeof(null))) { alias TypeParent = Seq!(); } else { alias TypeParent = Seq!(P!(T[0..T.length-1])); } } class Type(T...) : TypeParent!(Type!T) { int x; static if (T.length >= 1 && T[0] is "Animal") { int y; static if (T.length >= 2 && T[1] is "Dog") { int z; static if (T.length >= 3&& T[2] is "Pug") { int s; } } } } void main() { import std.traits; auto a = new Type!("Animal", "Dog", "Pug")(); Type!("Animal", "Dog") b = a; Type!("Animal") c = b; a.s = 1; b.z = 2; c.y = 3; } The problem is that b and c are of type P! Type!("Animal", "Dog", "Pug") P!("Animal", "Dog") P!"Animal" Of course, P should be Type and b.z and c.y should change a's variables. I don't know why alias TypeParent = Seq!(P!(T[0..T.length-1])); is returning P but I guess I'm doing it wrong. What I want is for it to return Type!(T[0],...,T[n-1]); Any ideas?
Re: CT Inheritence structures
On Saturday, 20 August 2016 at 09:42:08 UTC, Jack Applegame wrote: On Saturday, 20 August 2016 at 00:46:15 UTC, Engine Machine wrote: Any ideas? Something like this? mixin template TypeData(string type: "Animal") { int y; } mixin template TypeData(string type: "Dog") { int z; } mixin template TypeData(string type: "Pug") { int s; } template Type(string type, ARGS...) { static if(ARGS.length == 0) { class Type { mixin TypeData!type; } } else { class Type : Type!ARGS { mixin TypeData!type; } } } void main() { auto a = new Type!("Pug", "Dog", "Animal")(); Type!("Dog", "Animal") b = a; Type!("Animal") c = b; a.s = 1; b.z = 2; c.y = 3; pragma(msg, typeof(a)); pragma(msg, typeof(b)); pragma(msg, typeof(c)); } See result - https://dpaste.dzfl.pl/1a76490aaf55 No, this is just standard inheritance that has been complexified. The point is to have a single class that encapsulates it's own derived types. You have a type constructor. It also doesn't solve the original problem.
Re: CT Inheritence structures
On Saturday, 20 August 2016 at 06:28:47 UTC, Enamex wrote: On Saturday, 20 August 2016 at 00:46:15 UTC, Engine Machine wrote: I am trying to get Timon Gehr's code working, with some modifications: void main() { import std.traits; auto a = new Type!("Animal", "Dog", "Pug")(); Type!("Animal", "Dog") b = a; Type!("Animal") c = b; a.s = 1; b.z = 2; c.y = 3; } Also: alias T1 = TemplateOf!(typeof(a)); alias T2 = TemplateOf!(typeof(c)); pragma(msg, "\n", T1!"As", " -- ", T2!"As", "\n"); // T1!"As" -- T1!"As" That's extremely weird. It looks like template instantiations carry as their printable name (and comparison identifier, because `is(templateAlias == templateAlias2)` doesn't work) the name they were first instantiated through. So even doing: pragma(msg, T1!("Animal", "Dog")) would print `PT!("Animal", "Dog")` given that it had been instantiated already through another Type with ("Animal", "Dog") in the beginning of its tuple. So I guess this method simply won't work ;/ Or somehow TypeParent will have to construct the proper type indirectly, which may be impossible ;/ I'll try and work on it a little and see what happens.
Rebind template
Is there a way to rebind the arguments of a template? template foo(X) { // X is like A!(a,b,c) Y = Rebind!(X,d,e,f); // Y is like A!(d,e,f); } foo(A!(a,b,c)); ?
Re: Rebind template
On Saturday, 20 August 2016 at 22:11:40 UTC, Engine Machine wrote: Is there a way to rebind the arguments of a template? template foo(X) { // X is like A!(a,b,c) Y = Rebind!(X,d,e,f); // Y is like A!(d,e,f); } foo(A!(a,b,c)); ? I'd also be happy if I could just remove the last element from A. template EraseLast(X) { // returns A!(a,b) when X = A!(a,b,c) }
Re: Rebind template
On Saturday, 20 August 2016 at 22:21:00 UTC, ag0aep6g wrote: On 08/21/2016 12:11 AM, Engine Machine wrote: Is there a way to rebind the arguments of a template? template foo(X) { // X is like A!(a,b,c) Y = Rebind!(X,d,e,f); // Y is like A!(d,e,f); } foo(A!(a,b,c)); ? template Rebind(alias instance, newArgs...) { import std.traits: TemplateOf; alias tmpl = TemplateOf!instance; alias Rebind = tmpl!newArgs; } This doesn't work because the rebound type is of type tmpl and not the original e.g., Rebind!(T!b, a) is tmpl!a not T!a.
Re: Sequence separation
On Wednesday, 17 August 2016 at 18:38:48 UTC, Engine Machine wrote: On Wednesday, 17 August 2016 at 08:37:32 UTC, Lodovico Giaretta wrote: On Tuesday, 16 August 2016 at 23:18:28 UTC, Adam D. Ruppe wrote: [...] You mean something like: struct MySequence(Args...) { enum length = Args.length; alias args = Args; } alias x = MySequence!(a, b, MySequence!(c, d)); static assert(x.length == 3) static assert(x.args[2].length == 2); Thanks, basically works. How can I test, though, if a argument uses a MySequence? I can't do if (Args[0] == MySequence) because MySequence is templated. While I could test for a length, that doesn't work because some types have a length. I could add another enum to MySequence, but again, not safe. I could do some string tests, but that doesn't work. in your exmaple, if (x.args[2] == MySequence) ?? I simply need to differentiate between a parameter/arg being a MySequence and not. I guess I'll go with something like static if ((a.Args[2]).stringof[0..11] == "MySequence!") Doesn't feel entirely safe but probably will work without issue. Maybe there is a better way?
Re: Sequence separation
On Wednesday, 17 August 2016 at 19:15:48 UTC, ag0aep6g wrote: On 08/17/2016 08:38 PM, Engine Machine wrote: [...] [...] [...] With MySequence being a type, you can do this: static if (is(x.args[2] == MySequence!Args, Args ...)) { ... } It works! Nifty that you can do that with is. Aside from this check, there is probably not much use for MySequence being a type. So I'm be tempted to find a way to do the check with a raw template MySequence. As you said, another enum alone doesn't cut it. The faker can just add the same enum. But a private enum of a private type might do it: template MySequence(Args ...) { /* ... length and args ... */ private enum id = Id(); } private struct Id {} enum isMySequence(alias seq) = is(typeof(seq.id) == Id); Other modules can't use the Id type directly, because it's private. And they can't use typeof(MySequence!foo.id), because the id member is private, too. However, I wouldn't be surprised if this can be circumvented too. Well, the is does work and that probably is the best solution. I don't mind the extra type at this point. Of course, a library solution for this type of stuff would be nice. I'd rather not have to even use a type but rather use arrays: [a,b,[c,d]].
Re: Sequence separation
On Wednesday, 17 August 2016 at 19:21:57 UTC, Lodovico Giaretta wrote: On Wednesday, 17 August 2016 at 19:15:48 UTC, ag0aep6g wrote: [...] import std.traits: TemplateOf; static if (__traits(isSame, TemplateOf!(x.args[2]), MySequence)) { ... } std.traits.TemplateOf extracts the symbol representing the uninstantiated template. __traits(isSame, symbol1, symbol2) evaluates at compile time to true if and only if the two symbols represent the same thing (be it a type, an uninstantiated template, an instantiated one or whatever else). Thanks! To note, it error's if there is no match ;/
Re: Rebind template(bug?)
On Monday, 22 August 2016 at 22:52:28 UTC, ag0aep6g wrote: On Monday, 22 August 2016 at 21:46:35 UTC, Engine Machine wrote: I'm sorry if it confuses you... it doesn't confuse me. You needed quite some help to get this thing to work. And you made some mistakes and wrong statements in the process. That's perfectly fine, but please don't act as if Jack is the simpleton while you're the brainiac. Um, please don't be an arrogant prick. I never said anything about that. He says it confuses him, I said it doesn't confuse me. Getting it to work in D has nothing to do with understanding the structure. It's like saying that because you can't understand English that you must be an imbecile. I do not know why you have to try and prove something that is a preference. Jack showed a version which he thinks is "cleaner". And since this is a discussion board about code, it makes perfect sense for him to do that. If you don't care about it, you don't have to engage in discussion, of course. So? I am the one that asked the question how to do X. He brings up Y, then you try to justify Y. It is illogical and insane to do so. Do you often get in to arguments with people about how ford is better than chevy or blonds are better than brunettes? Please don't take this to a personal level. Jack was talking about the code, and you start questioning his character. Not cool. No, Jack is talking about Y and people that try to change topics, like you have done, is insane and do the same thing with what I have stated. Keep it up though. If you're happy with what you got, and you don't want to discuss other versions, you can say so without setting the stage for a shouting match. Simply not replying is an option, too. It may be a bit less polite, but it's better than escalating things. True, but then you should also take your own advice. But if a person can't be direct, honest, and talk specifically what is asked about, then it is already the well is already poisoned. But which will you option will you choose?
Virtual Classes?
https://en.wikipedia.org/wiki/Virtual_class Can D do stuff like this naturally?
Re: Rebind template(bug?)
On Monday, 22 August 2016 at 19:09:34 UTC, Jack Applegame wrote: On Monday, 22 August 2016 at 18:04:43 UTC, Engine Machine wrote: How do you seriously think this is cleaner/simpler? 1. No extra encrypted things, such as InstantiateOrEmptySeq 2. Much more understandable. You have two classes. No. I have one template with two specializations. Class template and class is not the same thing. Their is no uniformity between them. They have the same name. This is the best uniformity. You have uniformity between all the derived classes then have a special case for the base class. A certain easy to follow pattern is set up but needlessly break it for one case. Why? Because it is the base class. It has no parent. Also this is the standard and well known pattern in template metaprogramming. I'm sorry if it confuses you... it doesn't confuse me. I do not know why you have to try and prove something that is a preference. Do you often get in to arguments with people about how ford is better than chevy or blonds are better than brunettes?
Re: Rebind template(bug?)
On Monday, 22 August 2016 at 18:48:12 UTC, ag0aep6g wrote: On 08/22/2016 08:04 PM, Engine Machine wrote: How do you seriously think this is cleaner/simpler? You have two classes. Their is no uniformity between them. You have uniformity between all the derived classes then have a special case for the base class. A certain easy to follow pattern is set up but needlessly break it for one case. Why? It avoids the relatively obscure (and badly named, by me) InstantiateOrEmptySeq template. You can take this further with template constraints. Gives it a more uniform appearance at the price of some repetition: class T() { int x; } class T(A...) : T!(A[0..$-1]) if (A.length > 0 && A[$-1] == "Animal") { int y; } class T(A...) : T!(A[0..$-1]) if (A.length > 0 && A[$-1] == "Dog") { int z; } class T(A...) : T!(A[0..$-1]) if (A.length > 0 && A[$-1] == "Pug") { int s; } I wouldn't say that this is obviously, objectively, significantly better than the version with the helper template, though. Yeah, but a name means nothing. Change it if you want ;) By the way, it's not obvious to me what this whole thing achieves in practice. And whatever benefit there is, it has to be weighed against the cost of the added complexity. What it achieves is a uniform way to create a hierarchical relationship without excessive verbosity. Now, the static ifs are probably the most verbose part, a static switch would help: static switch (A) { case "Animal": return; ... } But only slightly. I don't mean to say that this is not worth pursuing. Just a friendly reminder that over-engineering is something to look out for, from someone who is prone to over-engineering himself. Ultimately it is just syntax, it does nothing over what D already does. It doesn't create anything new. In some cases it simplifies. If it does, then great, if it doesn't then don't use it. While I would prefer a totally different syntax, I also like to keep things organized. Having multiple classes floating around for certain things is just not needed so there should be an option.
Re: Rebind template(bug?)
On Monday, 22 August 2016 at 07:54:36 UTC, Jack Applegame wrote: On Monday, 22 August 2016 at 00:43:00 UTC, Engine Machine wrote: The following code works and does what I want! template InstantiateOrEmptySeq(alias tmpl, args...) { alias Seq(T...)=T; static if (args.length > 0) alias InstantiateOrEmptySeq = tmpl!(args[0 .. $-1]); else alias InstantiateOrEmptySeq = Seq!(); } class T(A...) : InstantiateOrEmptySeq!(T, A) { static if (A.length == 0) { // Base class int x; } else static if (A[$-1] == "Animal") { int y; } else static if (A[$-1] == "Dog") { int z; } else static if (A[$-1] == "Pug") { int s; } else static assert(A[$-1]~" not a defined class of "~this.stringof); } Why don't you like a cleaner (in my opinion) solution? class T() { // Base class int x; } class T(A...) : T!(A[0..$-1]) { static if (A[$-1] == "Animal") { int y; } else static if (A[$-1] == "Dog") { int z; } else static if (A[$-1] == "Pug") { int s; } else static assert(A[$-1]~" not a defined class of "~this.stringof); } How do you seriously think this is cleaner/simpler? You have two classes. Their is no uniformity between them. You have uniformity between all the derived classes then have a special case for the base class. A certain easy to follow pattern is set up but needlessly break it for one case. Why?
Re: Float values are wrong in union
On Monday, 22 August 2016 at 05:02:41 UTC, jkpl wrote: On Monday, 22 August 2016 at 04:52:40 UTC, Cauterite wrote: [...] That's a 32 bit codegen issue then because DMD64 's disasm shows that SSE regs are used: void foo() { union test { int i; float f; } test t = { i : 0x7fb0}; float t2 = t.f; test t3 = { f : t2 }; } === yields to === 004586D0h push rbp 004586D1h mov rbp, rsp 004586D4h sub rsp, 10h 004586D8h mov dword ptr [rbp-10h], 7FB0h 004586DFh movss xmm0, dword ptr [rbp-10h] 004586E4h movss dword ptr [rbp-0Ch], xmm0 004586E9h movss xmm1, dword ptr [rbp-0Ch] 004586EEh movss dword ptr [rbp-08h], xmm1 004586F3h leave 004586F4h ret === x86 give 7FF and x64 gives 7FB in win.