Re: how to achieve C's Token Pasting (##) Operator to generate variable name in D?
On Thursday, 4 June 2020 at 19:42:57 UTC, mw wrote: On Thursday, 4 June 2020 at 18:42:05 UTC, H. S. Teoh wrote: TBH, whenever I run into a diamond inheritance problem or similar, my first reaction is, I'm using the wrong tool for ^^ Haha, it's also because most of the populate OO languages didn't solve the diamond problem, and made the multiple inheritance hard to use in such situation, that's how the programmers learnt this "first reaction" from past bad experience. Conversely, if all the OO languages solved the diamond problem cleanly from the very start, the programmers will never learn such reaction.
Re: how to achieve C's Token Pasting (##) Operator to generate variable name in D?
On Thursday, 4 June 2020 at 18:42:05 UTC, H. S. Teoh wrote: TBH, whenever I run into a diamond inheritance problem or similar, my first reaction is, I'm using the wrong tool for modelling my data; I should be using some kind of component-based system instead of OO inheritance. I have no problem with whatever modelling technique the programmer want to choose. What I hate to see is: if a language does provide the OO mechanism, but having some loop-holes that causes trouble for the programmer who choose to use it. Esp. when these loop-holes are crept in after the language's initial design. (For example, I won't discuss multiple inheritance on a C forum, it's not that language designed for.)
Re: how to achieve C's Token Pasting (##) Operator to generate variable name in D?
On Thu, Jun 04, 2020 at 06:09:35PM +, mw via Digitalmars-d-learn wrote: [...] > -- > class Person : NameI, AddrI { > mixin NameT!Person rename equals as name_equals; > mixin AddrT!Person rename equals as addr_equals; > > bool equals(Person other) { > return this.name_equals(other) && >this.addr_equlas(other); > } > } > -- TBH, whenever I run into a diamond inheritance problem or similar, my first reaction is, I'm using the wrong tool for modelling my data; I should be using some kind of component-based system instead of OO inheritance. Nowadays I rarely use OO-style inheritance for data modelling anymore; it's still useful for rare cases where a straight hierarchy makes sense (traditional GUI widgets, for example, or parse trees), but for complex modelling I just stop pretending that there's a direct mapping from problem domain to language constructs, and instead build containers that have arbitrary component combinations as an infrastructure instead. Recently I've been dabbling in ECS (entity-component-system) adaptations from gamedev: the system part is not useful to me, but the idea behind entity-component storage is very useful for modelling complex data, much more suitable than traditional OO inheritance IMO. T -- I am Ohm of Borg. Resistance is voltage over current.
Re: how to achieve C's Token Pasting (##) Operator to generate variable name in D?
On Sunday, 31 May 2020 at 06:28:11 UTC, mw wrote: This is better, ... but it breaks std.traits: void main() { auto fields = FieldNameTuple!(Point); writeln(fields); } $ ./b varvarvar And normally, we cannot define 2 fields with different types: class P { int x; double x; // b.d(45): Error: variable b.P.x conflicts with variable b.P.x at b.d(44) } With the above template we somehow tricked the compiler to be able to do this? Is this a loop-hole we should file a bug? This is related to D's silent crept-in multiple inheritance problem, a solution via language improvement is here: https://forum.dlang.org/post/lsnhqdoyatkzbzqbs...@forum.dlang.org I'd imagine something like this: -- class Person : NameI, AddrI { mixin NameT!Person rename equals as name_equals; mixin AddrT!Person rename equals as addr_equals; bool equals(Person other) { return this.name_equals(other) && this.addr_equlas(other); } } --
Re: Fastest way to check using if identifier has already been defined, using static if or similar?
On Wednesday, 3 June 2020 at 09:03:22 UTC, drathier wrote: I'm generating some code. Some of the generated types need to be overridden, so I define them manually at the top of the generated file. Then I need to guard against redefining the identifier (type/value/function) later on, in the generated code. I'm currently using `static if (!__traits(compiles, thingy)) {` to avoid redefining things twice. Of course the proper fix is to not generate code for the identifiers which are already manually defined, and not generate any `static if`s at all, but until then, is there a faster way than `static if (__traits(compiles, ...` to check if a type/value/function has already been defined? This seems more complicated than I initially assumed. Is there a faster way if we separate the question to find just one of types, templates or top-level values at a time, into three different solutions? The definitions and static ifs are always always top level definitions/statements in my case.
Re: Is there a list of things which are slow to compile?
On Wednesday, 3 June 2020 at 17:02:35 UTC, H. S. Teoh wrote: On Wed, Jun 03, 2020 at 09:36:52AM +, drathier via Digitalmars-d-learn wrote: I'm wondering if there's a place that lists things which are slower/faster to compile? DMD is pretty famed for compiling quickly, but I'm not seeing particularly high speed at all, and I want to fix that. The two usual culprits are: - Recursive/chained templates - Excessive CTFE ... T Thanks for the comprehensive answer! I'm not using CTFE at all, because as you thought, Variants aren't supported in CTFE. I had to go out of my way to avoid CTFE running, since it crashes on Variants. I'm not using UFCS, and the long identifiers I was talking about are like 50 characters long, from mangling package name + module name + variable name together in the source language. I'm guessing it's mainly templates from my code gen then, and there's not much I can do about that; I'm doing code gen from a functional language where polymorphism is literally everywhere, and so are templates then. Regarding std.format, std.regex and such, would it be possible to put those into their own package or something, so `dub` doesn't rebuild them every time? It feels like that'd save a lot of time.
Re: Fastest way to check using if identifier has already been defined, using static if or similar?
On Thursday, 4 June 2020 at 14:20:45 UTC, Q. Schroll wrote: Little nitpicking, but D has many forms of string literals. Escaping is hard to read especially without syntax highlighting. Escaping to me is an old hack C did we shouldn't really use. string exists(string s) { return `__traits(compiles, { mixin("alias _ = ` ~ s ~ `;"); })`; } The _ as a name, to me, proves that a __traits(freshName), that returns a string that is distinct from every symbol name visible from the point it's defined, would be useful in these occasions. Because if someone used _ as an identifier in a context where the `exisits` function is used, it might fail. In the Lisp language family, this feature is called "gensym" (generate symbol). It is indeed quite useful to have when generating code. I believe it was proposed at one point to add a special __GENSYM__ keyword, similar to the current __FILE__, __LINE__, __MODULE__, etc. that would evaluate to a unique identifier each time it was used. I'm not sure what became of that proposal. Maybe it needed a DIP and no one was available to write one?
Re: Fastest way to check using if identifier has already been defined, using static if or similar?
On Thursday, 4 June 2020 at 14:20:45 UTC, Q. Schroll wrote: On Thursday, 4 June 2020 at 09:03:40 UTC, Simen Kjærås wrote: string exists(string s) { return "__traits(compiles, { mixin(\"alias _ = "~s~";\"); })"; } Little nitpicking, but D has many forms of string literals. Escaping is hard to read especially without syntax highlighting. Escaping to me is an old hack C did we shouldn't really use. string exists(string s) { return `__traits(compiles, { mixin("alias _ = ` ~ s ~ `;"); })`; } The _ as a name, to me, proves that a __traits(freshName), that returns a string that is distinct from every symbol name visible from the point it's defined, would be useful in these occasions. Because if someone used _ as an identifier in a context where the `exisits` function is used, it might fail. Don't have a unique name facility now? ... I remember seeing one. Could have been a mirage I guess.
Re: Fastest way to check using if identifier has already been defined, using static if or similar?
On Thursday, 4 June 2020 at 09:03:40 UTC, Simen Kjærås wrote: string exists(string s) { return "__traits(compiles, { mixin(\"alias _ = "~s~";\"); })"; } Little nitpicking, but D has many forms of string literals. Escaping is hard to read especially without syntax highlighting. Escaping to me is an old hack C did we shouldn't really use. string exists(string s) { return `__traits(compiles, { mixin("alias _ = ` ~ s ~ `;"); })`; } The _ as a name, to me, proves that a __traits(freshName), that returns a string that is distinct from every symbol name visible from the point it's defined, would be useful in these occasions. Because if someone used _ as an identifier in a context where the `exisits` function is used, it might fail.
Re: Fastest way to check using if identifier has already been defined, using static if or similar?
On Wednesday, 3 June 2020 at 15:25:51 UTC, Paul Backus wrote: On Wednesday, 3 June 2020 at 13:24:17 UTC, Basile B. wrote: This is because the template parameter must be resolved to a valid symbol or type. This version other version bypass the problem: --- enum Exists(string s) = is(typeof(mixin(s))); void main() { static if (!Exists!"foo") int foo; foo = 42; } --- Fails if the symbol in question is the name of a type. struct Foo {} enum Exists(string s) = is(typeof(mixin(s))); static assert(Exists!"Foo"); // false What you actually want is something like this: enum Exists(string s) = __traits(compiles, { mixin("alias _ = ", s, ";"); }); And they both fail if the thing you refer to isn't available in the scope where Exists is defined. I believe this covers most cases, but there may very well be corner cases I haven't considered: string exists(string s) { return "__traits(compiles, { mixin(\"alias _ = "~s~";\"); })"; } // Handles values: int global; unittest { int local; { int outOfScope; } static assert(mixin("local".exists)); static assert(mixin("global".exists)); static assert(!mixin("outOfScope".exists)); } // And types: struct Global {} unittest { struct Local {} { struct OutOfScope; } static assert(mixin("Global".exists)); static assert(mixin("Local".exists)); static assert(!mixin("OutOfScope".exists)); } // But not expressions: static assert(!mixin("1+2".exists)); // Correctly fails for missing declarations: static assert(!mixin("nowhere".exists)); Like Stefan said though, we're quite a bit off from the original request - the above certainly shouldn't be faster than drathier's original code. The only advantage I see is that it might read a little clearer. -- Simen