Re: How to use destroy and free.
On Wednesday, 4 May 2022 at 05:13:04 UTC, Mike Parker wrote: On Wednesday, 4 May 2022 at 04:52:05 UTC, forkit wrote: It is certainly *not* about you not having to care anymore (about memory management). That's not at all what I said. You don't have to care about *when* memory is deallocated, meaning you don't have to manage it yourself. In any case, I disagree that caring about when memory gets deallocted means you shouldn't be using GC. (or did I get that one wrong too??) You can have the best of both worlds, surely (and easily). This (example from first post): void main(){ int[] i = new int[1]; import object: destroy; destroy(i); import core.memory: GC; GC.free(GC.addrOf(cast(void *)(i.ptr))); } could (in theory) be replaced with this: void main(){ inscope int[] i = new int[1]; // inscope means 2 things: // (1) i cannot be referenced anywhere except within this scope. // (2) i *will* be GC'd when this scope ends }
Re: How to use destroy and free.
On Wednesday, 4 May 2022 at 04:52:05 UTC, forkit wrote: It is certainly *not* about you not having to care anymore (about memory management). That's not at all what I said. You don't have to care about *when* memory is deallocated, meaning you don't have to manage it yourself.
Re: How to use destroy and free.
On Wednesday, 4 May 2022 at 02:42:44 UTC, Mike Parker wrote: On Tuesday, 3 May 2022 at 14:57:46 UTC, Alain De Vos wrote: Note, It's not i'm against GC. But my preference is to use builtin types and libraries if possible, But at the same time be able to be sure memory is given free when a variable is going out of scope. It seems not easy to combine the two with a GC which does his best effort but as he likes or not. What I described is an optional compiler optimization. The compiler is free to avoid the GC allocation for an array literal initializer if it is possible to do so. If you were to, e.g., return the array from the function, it would 100% for sure be allocated on the GC and not the stack. In practice, I don't know if any of the compilers actually do this. Anyway, if you care when memory is deallocated, then the GC isn't the right tool for the job. The point of the GC is that you don't have to care. GC is about reducing the complexity, cognitive load, and possible bugs - associated with manual memory management. It is certainly *not* about you not having to care anymore (about memory management). Why not have an option to mark an object, so that real-time garbage collection occurs on it as it exits scope?
Re: How to use destroy and free.
On Tuesday, 3 May 2022 at 14:57:46 UTC, Alain De Vos wrote: Note, It's not i'm against GC. But my preference is to use builtin types and libraries if possible, But at the same time be able to be sure memory is given free when a variable is going out of scope. It seems not easy to combine the two with a GC which does his best effort but as he likes or not. What I described is an optional compiler optimization. The compiler is free to avoid the GC allocation for an array literal initializer if it is possible to do so. If you were to, e.g., return the array from the function, it would 100% for sure be allocated on the GC and not the stack. In practice, I don't know if any of the compilers actually do this. Anyway, if you care when memory is deallocated, then the GC isn't the right tool for the job. The point of the GC is that you don't have to care.
Re: Parameters declared as the alias of a template won't accept the arguments of the same type.
On Tuesday, 3 May 2022 at 15:41:08 UTC, Ali Çehreli wrote: We also have NP-completeness. Ok, so C++ has similar limitations when you have a template with an unknown parameter in a function parameter, but is this because it would be NPC? Also, do we know that it cannot be resolved for the typical case in reasonable time? Maybe one can add constraints and heuristics that keeps it reasonable? No, the question is whether D is in a category of programming languages that it isn't. Fair enough, but type unification needs to be done differently anyway, just to support aliases being recognized in function calls. Why not look at what is possible before going there? Certainly, having something more expressive than C++ would not be a bad thing?
Re: String Literals
On Tuesday, 3 May 2022 at 17:21:47 UTC, JG wrote: Hi, The specification of string literals has either some errors or I don't understand what is meant by a Character. [...] Which to me means that e.g. r""" should be a WysiwygString, which the compiler thinks is not (not surprisingly). Am I misunderstanding something? The rule is not correct but the implementation in the lexer is. That's a valid issue for dlang.org
Re: DMD failed with exit code -1073741819
On Tuesday, 3 May 2022 at 19:03:56 UTC, Dennis wrote: On Tuesday, 3 May 2022 at 18:22:49 UTC, jmh530 wrote: Does anyone have any idea what causes these types of errors? Sounds like a stack overflow, maybe your code has a complex/recursive part that makes DMD's call stack very deep. Thanks. I think this was it. I figured it out, but it took a bit of time to identify where the problem was coming from... Basically, I started out with a template like ```d template foo(T, U u = val, V, W) {} ``` and refactored it to ```d template foo(T, U u = val, V, W, U y = u) {} ``` which is when I started getting the problem, but I had changed a bunch of other stuff to introduce `y`, so it wasn't entirely clear why that would cause the problems. Anyway, changing it to ```d template foo(T, U u = val, V, W, U y = val) {} ``` made the problem went away.
Re: DMD failed with exit code -1073741819
On Tuesday, 3 May 2022 at 18:22:49 UTC, jmh530 wrote: Does anyone have any idea what causes these types of errors? Sounds like a stack overflow, maybe your code has a complex/recursive part that makes DMD's call stack very deep.
Re: DMD failed with exit code -1073741819
On Tuesday, 3 May 2022 at 18:22:49 UTC, jmh530 wrote: I was leaning towards it being something related to running out of memory or something, but I'm using dub and I've tried turning on and off "lowmem". Note that dub cannot pass -lowmem to dmd. https://issues.dlang.org/show_bug.cgi?id=20699
DMD failed with exit code -1073741819
I made some changes to some code I'm working on and now there are some lines that are giving me funky DMD error codes (I can tell it is some lines because I comment them out and the errors go away). So for instance, one line I have a static assert that gives an error code -1073741819, but if I split it up into two pieces (so that part of it is assigned to a value and then I use typeof that value in the static assert), then DMD does not complain. Does anyone have any idea what causes these types of errors? I was leaning towards it being something related to running out of memory or something, but I'm using dub and I've tried turning on and off "lowmem". I also have used -v both in dflags and at the command line and haven't noticed any obvious errors.
Re: How to get compatible symbol names and runtime typeid names for templated classes?
On Tue, May 03, 2022 at 05:25:06PM +, cc via Digitalmars-d-learn wrote: > On Tuesday, 3 May 2022 at 17:05:09 UTC, H. S. Teoh wrote: > > Oops, sorry, I made a mistake. The definition of Serializable should be: > > > > class Serializable(Base, Derived = Object) : Base {} > > There we go, works with this, now I get what it's trying to do: > ```d > class Serializable(Base, Derived = Object) : Derived { > ``` > > What's the purpose of the `static struct Proxy`? The `static this()` > seems to work without being enclosed in a structure. Actually, come to think of it, Proxy isn't strictly necessary. You could move the static this into Serializable and it'd work. The main purpose here is to create a separate instance of static this() per instantiation of Serializable, i.e., there'd be a separate instance of static this() for each Derived class. Since the compiler collects all static this()'s into a list of functions that run at program startup, this allows us to initialize the deserializers AA with functions that understand how to create an instance of Derived at runtime. Since in the scope of the static this we have direct access to compile-time information about Derived, it can use compile-time introspection to inspect Derived and take the appropriate action at runtime based on this compile-time knowledge. In this way, we "translate" compile-time knowledge into runtime knowledge. T -- PNP = Plug 'N' Pray
Re: How to get compatible symbol names and runtime typeid names for templated classes?
On Tuesday, 3 May 2022 at 17:05:09 UTC, H. S. Teoh wrote: Oops, sorry, I made a mistake. The definition of Serializable should be: class Serializable(Base, Derived = Object) : Base {} There we go, works with this, now I get what it's trying to do: ```d class Serializable(Base, Derived = Object) : Derived { ``` What's the purpose of the `static struct Proxy`? The `static this()` seems to work without being enclosed in a structure.
String Literals
Hi, The specification of string literals has either some errors or I don't understand what is meant by a Character. For instance we have: WysiwygString: r" WysiwygCharacters_opt " StringPostfix_opt WysiwygCharacters: WysiwygCharacter WysiwygCharacter WysiwygCharacters WysiwygCharacter: Character EndOfLine Character: any Unicode character Which to me means that e.g. r""" should be a WysiwygString, which the compiler thinks is not (not surprisingly). Am I misunderstanding something?
Re: How to get compatible symbol names and runtime typeid names for templated classes?
On Tue, May 03, 2022 at 04:59:42PM +, cc via Digitalmars-d-learn wrote: > On Tuesday, 3 May 2022 at 16:51:33 UTC, H. S. Teoh wrote: [...] > > > On Tuesday, 3 May 2022 at 15:08:53 UTC, H. S. Teoh wrote: > > > > class Base : Serializable!(Base) { ... } > > > > class Derived : Serializable!(Base, Derived) { ... } [...] > Hm although I am having trouble with that particular implementation: > ```d > class Base : Serializable!(Base) {} > class Derived : Serializable!(Base, Derived) {} > class Serializable(Base, Derived = Base) : Base {} > ``` > ``` > Error: class `test.Base` circular inheritance > Error: template instance `test.Serializable!(Base, Base)` error > instantiating > ``` Oops, sorry, I made a mistake. The definition of Serializable should be: class Serializable(Base, Derived = Object) : Base {} and the corresponding static if in the implementation should test for Object instead of Base. Basically, it's just some way of differentiating the base class from the derived classes, because you need to declare the serialize methods in the base class without `override` but in the derived classes you need `override`. T -- Turning your clock 15 minutes ahead won't cure lateness---you're just making time go faster!
Re: How to get compatible symbol names and runtime typeid names for templated classes?
On Tuesday, 3 May 2022 at 16:51:33 UTC, H. S. Teoh wrote: On Tue, May 03, 2022 at 04:38:23PM +, cc via Digitalmars-d-learn wrote: On Tuesday, 3 May 2022 at 15:08:53 UTC, H. S. Teoh wrote: >class Base : Serializable!(Base) { ... } >class Derived : Serializable!(Base, Derived) { ... } This is really interesting syntax, I'm surprised that works! https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern It's a bit counterintuitive at first, but once you "get" how it works, it's an extremely powerful technique for leveraging D's compile-time introspection capabilities. And translating compile-time information into runtime using static this(). ;-) T Hm although I am having trouble with that particular implementation: ```d class Base : Serializable!(Base) {} class Derived : Serializable!(Base, Derived) {} class Serializable(Base, Derived = Base) : Base {} ``` ``` Error: class `test.Base` circular inheritance Error: template instance `test.Serializable!(Base, Base)` error instantiating ```
Re: How to get compatible symbol names and runtime typeid names for templated classes?
On Tuesday, 3 May 2022 at 16:38:23 UTC, cc wrote: This is really interesting syntax, I'm surprised that works! Can read a little more on my blog about it: http://dpldocs.info/this-week-in-d/Blog.Posted_2019_06_10.html#tip-of-the-week pretty cool little pattern.
Re: How to get compatible symbol names and runtime typeid names for templated classes?
On Tue, May 03, 2022 at 04:38:23PM +, cc via Digitalmars-d-learn wrote: > On Tuesday, 3 May 2022 at 15:08:53 UTC, H. S. Teoh wrote: > > class Base : Serializable!(Base) { ... } > > class Derived : Serializable!(Base, Derived) { ... } > > This is really interesting syntax, I'm surprised that works! https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern It's a bit counterintuitive at first, but once you "get" how it works, it's an extremely powerful technique for leveraging D's compile-time introspection capabilities. And translating compile-time information into runtime using static this(). ;-) T -- Never step over a puddle, always step around it. Chances are that whatever made it is still dripping.
Re: How to use destroy and free.
On Tuesday, 3 May 2022 at 12:59:31 UTC, Alain De Vos wrote: Error: array literal in @nogc function test.myfun may cause a GC allocation @nogc void myfun(){ scope int[] i=[1,2,3]; }//myfun May is a fuzzy word... For this particular piece of code, you can use a static array to guarantee the usage of stack allocation ```d import std; @nogc void myfun(){ /* no need to use scope now */int[3] i=[1,2,3];//this now compiles }//myfun void main() { writeln("Hello D"); } ```
Re: How to get compatible symbol names and runtime typeid names for templated classes?
On Tuesday, 3 May 2022 at 15:08:53 UTC, H. S. Teoh wrote: class Base : Serializable!(Base) { ... } class Derived : Serializable!(Base, Derived) { ... } This is really interesting syntax, I'm surprised that works!
Re: Parameters declared as the alias of a template won't accept the arguments of the same type.
On 5/2/22 13:36, Stanislav Blinov wrote: >> That's fine because D does not promise to solve such problems. It >> follows simple deduction rules. > > Words, dear guru. Words have a meaning. It is very possible to deduce > here (note the premise). D just isn't trying. That's what I said. You > can say "it doesn't promise". Doesn't exactly change the meaning, does > it? :) What I mean is, problem solving the way you expect is not in D's charter. >> > The function takes an int. >> >> How would the solution be? Wouldn't the compiler have to parse all >> accessible template bodies to figure out which ones fit? > > Err... yes? That's what it *is* doing already, for all templates. No, the compiler does not parse all templates. Only the ones that needs instantiation. >> Imagine the following two other templates: >> >> template YourAlias(T) { >> alias YourAlias = int; // Is it this one? >> } >> >> template HerAlias(T) { >> // ... >> alias HerAlias = HisAlias!SomeNameInThisScope; // Or thi? >> } > > No. HerAlias and YourAlias are different symbols. You are right. I confused myself there but it is not that different when we stay with MyAlias alone. I am changing 'int' to YourAlias!T: template MyAlias(T){ alias MyAlias = YourAlias!T; } Do you still expect the compiler to dig into YourAlias and solve a problem to see whether YourAlias can be the same as aliasing 'int'? Would that enough trying by the compiler? If not, where should the compiler stop? In any case, that is not what D is. That's what I meant. Not being even a junior guru, I don't know what categories of programming languages do that. Declarative? Logic? All I know is D is not among them. >> The compiler would have to solve this problem by digging into >> HisAlias's SomeNameInThisScope instantiation as well. As far as know, >> the D language does not work that way. Prolog and friends perhaps? > > Nope. MyAlias is an alias. A template alias, but an alias nonetheless. > It should be resolved prior to trying the overloads. Not going to happen. >> > Doesn't take a rocket >> > scientist to figure that one out. >> >> I think this is one of those cases where it is easier for a human. >> Although, I think I would have difficulty if there were more than one >> template parameter. > > That's what we have compilers for. We also have NP-completeness. >> > I might as well forego the templates and >> > just write explicit overloads. At which point I would >> question why use >> > templates at all. >> >> Templates allow single implementations to work for many types, >> manifest constants, aliases, etc. I wouldn't want to write (or >> mix-in?) sort() for MyType. Templates are wonderful and their >> implementation in D is refreshing. > > It is, until is isn't. Question du jeour is one of those. No, the question is whether D is in a category of programming languages that it isn't. Ali
Re: How to get compatible symbol names and runtime typeid names for templated classes?
On 3/5/22 16:48, Adam D Ruppe wrote: Believe it or not, you don't need to touch the compiler. Open your druntime's object.d and search for `RTInfo` http://druntime.dpldocs.info/object.RTInfo.html That is instantiated for every user defined type in the program and you have the compile time info. all druntime uses it for is a tiny bit of GC info and even then only sometimes. But it could do so so so much more. Including doing custom factories and runtime reflection buildups! This looks nice, but I actually meant to allow "template this" in static contexts, as in the bug reports. I think that might indeed need compiler support? You'll make me happy if that's possible without touching the compiler!
Re: How to use destroy and free.
On 5/3/22 07:57, Alain De Vos wrote: > But at the same time be able to be sure memory is given free when a > variable is going out of scope. Let's expand on that please. What exactly is the worry there? Are you concerned that the program will have memory leaks, and eventually got killed by the OS? Do you want memory to be freed all the way to the OS? Would it be possible that a call to some_library_free() puts that memory in a free list to be used for later allocations? Or do you insist that memory really goes back to the OS? Why are you worried about how memory is managed? The way I think is this: When I use some feature and that feature allocates memory, it is not up to me to free memory at all. I don't want to get involved in how that memory is managed. On the other hand, if I were the party that did allocate memory, fine, then I might be involved in freeing. Note that 'new' is not raw memory allocation. So it should not involve raw memory freeing. Sorry for all the questions but I am really curious why. At the same time, I have a suspicion: You come from a language like C++ that thinks deterministic memory freeing is the only way to go. It took me many years to learn that C++'s insintence on that topic is wrong. Memory can be freed altogether at some later time. Further, not every object needs to be destroyed. These are based on one of John Lakos's C++Now presentations where he shows comparisons of different destruction and freeing schemes where (paraphrasing) "no destruction whatsoever; poof the array disappears." Not surprisingly, that happens to be the fastest destruction plus free. Ali
Re: How to use destroy and free.
On Tue, May 03, 2022 at 02:57:46PM +, Alain De Vos via Digitalmars-d-learn wrote: > Note, It's not i'm against GC. But my preference is to use builtin > types and libraries if possible, > But at the same time be able to be sure memory is given free when a > variable is going out of scope. > It seems not easy to combine the two with a GC which does his best > effort but as he likes or not. If your objects have a well-defined lifetime and you want to control when they get freed, just use malloc/free or equivalents (use emplace to initialize the object in custom-allocated memory). Don't use the GC. Using the GC means you relinquish control over when (and in what order) your objects get freed. T -- There's light at the end of the tunnel. It's the oncoming train.
Re: How to get compatible symbol names and runtime typeid names for templated classes?
On Tue, May 03, 2022 at 04:38:53PM +0200, Arafel via Digitalmars-d-learn wrote: > On 3/5/22 15:57, Adam D Ruppe wrote: > > So doing things yourself gives you some control. > > Yes, it is indeed possible (I acknowledged it), but I think it's much > more cumbersome than it should, and puts the load on the user. > > If templated this worked in static context (ideally everywhere else > too), then we'd be able to implement RTTI in a 100% "pay as you go" > way: just inherit from SerializableObject, or perhaps add a mixin to > your own root class, and that'd be it. > > Actually, it would be cool to do it through an interface, although I > don't think an interface's static constructors are invoked by the > implementing classes... it would be cool, though. The way I did it in my own serialization code is to use CRTP with static ctors in templated wrapper structs. Namely, replace: class Base { ... } class Derived : Base { ... } with: class Base : Serializable!(Base) { ... } class Derived : Serializable!(Base, Derived) { ... } That's the only thing user code classes need to do. The rest is done in the Serializable proxy base class using compile-time introspection. In a nutshell, what Serializable does is to inject serialize() and deserialize() methods into the class hierarchy. Here's a brief sketch of what it looks like: class Serializable(Base, Derived = Base) : Base { static if (is(Base == Derived)) // this is the base of the hierarchy { // Base class declarations void serialize(...) { ... // use introspection to extract data members } void deserialize(...) { ... // use introspection to reconstitute data members } } else // this is a derived class in the hierarchy { override void serialize(...) { ... // use introspection to extract data members } override void deserialize(...) { ... // use introspection to reconstitute data members } } // How does the deserializer recreate an instance of // Derived? By registering the string name of the class // into a global hash: static struct Proxy // N.B.: this is instantiated for each Derived class { // This static this gets instantiated per // Derived class, and uses compile-time // knowledge about Derived to generate code for // reconstructing an instance of Derived. static this() { deserializers[Derived.stringof] = { auto obj = new Derived(); obj.deserialize(...); return obj; }; } } } // This is module-global. /*shared*/ static Object delegate(...)[string] deserializers; // Global deserialize method that returns an instance of the // class hierarchy. Object deserialize(...) { // Obtain class name from serialized data string classname = ...; // Dispatch to the correct method registered by Proxy's // static this, that recreates the class of the required // type. return deserializers[classname](...); } The nice thing about this approach is that you have full compile-time information about the target type `Derived`, in both the serialization and deserialization methods. So you can use introspection to automate away most of the boilerplate associated with serialization code. E.g., iterate over __traits(allMembers) to extract data fields, inspect UDAs that allow user classes to specify how the serialization should proceed, etc.. 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: How to use destroy and free.
Note, It's not i'm against GC. But my preference is to use builtin types and libraries if possible, But at the same time be able to be sure memory is given free when a variable is going out of scope. It seems not easy to combine the two with a GC which does his best effort but as he likes or not.
Re: How to get compatible symbol names and runtime typeid names for templated classes?
On Tuesday, 3 May 2022 at 14:38:53 UTC, Arafel wrote: Actually, it would be cool to do it through an interface, although I don't think an interface's static constructors are invoked by the implementing classes... it would be cool, though. yeah interfaces can't have constructors. I'd try it myself, but I wouldn't know where to start. Compiler internals are way beyond my comfort zone... Believe it or not, you don't need to touch the compiler. Open your druntime's object.d and search for `RTInfo` http://druntime.dpldocs.info/object.RTInfo.html That is instantiated for every user defined type in the program and you have the compile time info. all druntime uses it for is a tiny bit of GC info and even then only sometimes. But it could do so so so much more. Including doing custom factories and runtime reflection buildups!
Re: How to get compatible symbol names and runtime typeid names for templated classes?
On 3/5/22 15:57, Adam D Ruppe wrote: So doing things yourself gives you some control. Yes, it is indeed possible (I acknowledged it), but I think it's much more cumbersome than it should, and puts the load on the user. If templated this worked in static context (ideally everywhere else too), then we'd be able to implement RTTI in a 100% "pay as you go" way: just inherit from SerializableObject, or perhaps add a mixin to your own root class, and that'd be it. Actually, it would be cool to do it through an interface, although I don't think an interface's static constructors are invoked by the implementing classes... it would be cool, though. And, in one of the bugs, you argue yourself that according to the spec, it *should* work. So please let me just whine... I mean, raise awareness ;-), in case somebody thinks it's interesting and feels brave enough to have a go at it. I'd try it myself, but I wouldn't know where to start. Compiler internals are way beyond my comfort zone...
Re: How to get compatible symbol names and runtime typeid names for templated classes?
On Tuesday, 3 May 2022 at 13:25:14 UTC, Arafel wrote: I'd like to do a runtime registration system myself, using a "template this" static constructor. A simple version supporting only default constructors would be: Yeah, you can't template this a static constructor, but you can just use a static constructor. It will have to be mixed into each child class though, and the compiler won't help to remind you. But do something along the lines of: ```d module factory.register; private Object function()[string] factories; Object construct(string name) { if(auto f = name in factories) return (*f)(); return null; } mixin template Register() { static this() { import factory.register; alias This = typeof(this); // bypassing private __traits(getMember, factory.register, "factories") [This.mangleof] = function Object() { // you could even delegate to a static // function if one is present, or pass arguments // etc. this impossible with Object.factory return new This(); }; } } ``` That code is your library. Then, to use it: ```d import factory.register; class MyThing { // you have to remember to do this in each child mixin Register; } void main() { auto t = new MyThing(); // I used the mangle instead of the FQN since it // is easier. Object o = construct(typeof(t).mangleof); MyThing t2 = cast(MyThing) o; assert(t2 !is null); // assert it actually worked } ``` Now, you can extend this a little if you're willing to add an interface too. And if you forget to register the base class, the interface method being not implemented will remind user they did something wrong, and you can runtime assert to check child classes. Check this out: ```d module factory.register; private Object function()[string] factories; Object construct(string name) { if(auto f = name in factories) return (*f)(); return null; } // adding this for the assert bool typeIsRegistered(string name) { return (name in factories) !is null; } // this interface gives runtime access to the info we need interface Serializable { string typeCode() const; } mixin template Register() { // interface implementation override string typeCode() const { // casting away const for more consistent names alias no_const = typeof(cast() this); auto name = no_const.mangleof; // a runtime check to help remind you if something not registered import factory.register; assert(typeIsRegistered(name), "Type "~typeof(this).stringof~" not registered!"); // also making sure the child class was registered // by ensuring the runtime type is the same as the static type assert(typeid(this) == typeid(no_const), "Child class "~typeid(this).toString()~" was not registered!"); return name; } static this() { import factory.register; alias This = typeof(this); // bypassing private __traits(getMember, factory.register, "factories") [This.mangleof] = function Object() { // you could even delegate to a static // function if one is present, or pass arguments // etc. this impossible with Object.factory return new This(); }; } } ``` And the usage: ```d import factory.register; class MyThing : Serializable { mixin Register; } class Child : MyThing { // forgot to register uh oh // mixin Register; } void main() { auto t = new MyThing(); Object o = construct(typeof(t).mangleof); MyThing t2 = cast(MyThing) o; assert(t2 !is null); auto child = new Child(); // if we called this in the serialize function or even one of those constructors' contracts // it can verify things work by triggering the asserts back in the library implementation child.typeCode(); } ``` So doing things yourself gives you some control.
Re: How to use destroy and free.
On Tuesday, 3 May 2022 at 12:59:31 UTC, Alain De Vos wrote: Error: array literal in @nogc function test.myfun may cause a GC allocation @nogc void myfun(){ scope int[] i=[1,2,3]; }//myfun May is a fuzzy word... It means if the compiler is free to allocate on the stack if possible. In practice, though, you can usually assume there will be a GC allocation.
Re: How to get compatible symbol names and runtime typeid names for templated classes?
On 3/5/22 14:46, Adam D Ruppe wrote: Put a static constructor in the class which appends a factory delegate to an array or something you can use later. Then you can use your own thing to construct registered objects. I'd like to do a runtime registration system myself, using a "template this" static constructor. A simple version supporting only default constructors would be: ```d module test; import std.stdio : writeln; class MyObject { /* static */ this(this T)() { string type = typeid(T).name; if (type !in generators) { generators[type] = () => new T(); } } static MyObject factory(string type) { if(type in generators) { return generators[type](); } else { return null; } } private: static MyObject function()[string] generators; } class MyClass : MyObject { this() { writeln("Creating MyClass"); } } void main() { auto _ = new MyClass(); // Shouldn't be needed auto myClass = MyObject.factory("test.MyClass"); } ``` Unfortunately, this isn't currently possible: https://issues.dlang.org/show_bug.cgi?id=10488 https://issues.dlang.org/show_bug.cgi?id=20277 (notice the big number of duplicates). The closest feasible option is to put it in a non-static constructor, and that's suboptimal: it forces an instantiation of the class, and it will be run at every instantiation. Alternatively, instruct the users to create a static constructor for each of the classes they'd like registered (perhaps through a mixin), but that's also quite cumbersome.
Re: How to get compatible symbol names and runtime typeid names for templated classes?
On Tuesday, 3 May 2022 at 10:48:53 UTC, bauss wrote: Object.factory calls TypeInfo_Class.find which just loops through ModuleInfo and then looks if any of the entries in localClasses has a name that matches. Afterwards it calls the create function on the TypeInfo_Class which of course isn't "generic" by any means. This is where compile-time has its limits compared to runtime type creation, because templates only live during compile-time then it isn't really that easy to do something like this, where it would be trivial in other languages like C#. On Tuesday, 3 May 2022 at 12:46:56 UTC, Adam D Ruppe wrote: On Tuesday, 3 May 2022 at 09:42:45 UTC, cc wrote: something I can pass to `Object.factory`. Object.factory is useless and will hopefully be removed someday. Instead, make your own factory registration function. Put a static constructor in the class which appends a factory delegate to an array or something you can use later. Then you can use your own thing to construct registered objects. Yeah, that's unfortunate. Actually I was already doing something similar for serialization/encoding to get the true type of an object (making sure `Animal an = new Cat();` encodes a Cat and not an Animal), took me a second to put two and two together and realize I could just instantiate objects via new that way instead of calling Object.factory. At the moment I try to register as many relevant symbols as I can automatically when encoding is called for a given object, such as: ```d private mixin template RegisterModule(alias MOD) { void RegisterModule() { static foreach (SYM; getSymbolsByUDA!(MOD, Coder)) { static if (is(SYM == class)) { RegisterSerializer!SYM(); } } } } private static void[0][string] registeredModules; private void registerModules(T)() { enum string MODULENAME = moduleName!T; if (MODULENAME !in registeredModules) { registeredModules.require(MODULENAME); mixin("import "~MODULENAME~";"); mixin("mixin RegisterModule!"~MODULENAME~";"); RegisterModule(); } } IPtr encode(T)(T obj) { registerModules!T; ... } ``` I'll have to get a little more creative for registering templated classes then, something like this works: ```d static void RegisterSerializer(alias SYM)(string runtimeName = null) { enum sym = fullyQualifiedName!SYM; if (sym !in serialTypes) { auto st = new SerialType!SYM; serialTypes[sym] = st; if (runtimeName.length && runtimeName !in serialTypes) serialTypes[runtimeName] = st; } } static void RegisterSerializer(T : Object)(T obj) { RegisterSerializer!T(typeid(obj).name); } ``` but I'd rather not have to instantiate an actual object just to get its typeid().name, I suppose I can just manually construct it from the fullyQualifiedName inserting the parenthesis and appended portion so it matches.
Re: How to use destroy and free.
Error: array literal in @nogc function test.myfun may cause a GC allocation @nogc void myfun(){ scope int[] i=[1,2,3]; }//myfun May is a fuzzy word...
Re: How to get compatible symbol names and runtime typeid names for templated classes?
On Tuesday, 3 May 2022 at 09:42:45 UTC, cc wrote: something I can pass to `Object.factory`. Object.factory is useless and will hopefully be removed someday. Instead, make your own factory registration function. Put a static constructor in the class which appends a factory delegate to an array or something you can use later. Then you can use your own thing to construct registered objects.
Re: How to get compatible symbol names and runtime typeid names for templated classes?
On 3/5/22 12:48, bauss wrote: This is where compile-time has its limits compared to runtime type creation, because templates only live during compile-time then it isn't really that easy to do something like this, where it would be trivial in other languages like C#. That's something I don't really get. I totally understand that you can't instantiate the template during runtime, but why can't already instantiated classes be registered just like non-templated ones? I tried the following snippet, and couldn't find C!int.C anywhere, although it **must** be there: I can get the `TypeInfo_Class` object, so I can clearly create new instances at runtime: ```d import std.stdio : writeln; class C(T) {} class D {} void main() { auto c = new C!int(); auto c2 = typeid(c).create(); auto d = new D(); writeln(typeid(c).name); writeln(typeid(c2).name); writeln(typeid(d).name); writeln(""); writeln; writeln; foreach (m; ModuleInfo) { if (m) { writeln(m.name); writeln(""); foreach (c; m.localClasses) { if (c) { writeln(c.name); } } writeln; } } } ```
Re: How to get compatible symbol names and runtime typeid names for templated classes?
On Tuesday, 3 May 2022 at 09:52:56 UTC, cc wrote: On Tuesday, 3 May 2022 at 09:42:45 UTC, cc wrote: Given a runtime typeid, how can I get the equivalent fullyQualifiedName without attempting to mangle the string myself manually? e.g. something I can pass to `Object.factory`. Actually, looking at this further, does Object.factory even support templates? I'm getting null returned from any attempt to instantiate a templated classname. It does not. Object.factory calls TypeInfo_Class.find which just loops through ModuleInfo and then looks if any of the entries in localClasses has a name that matches. So for your example it does this check: ``` if (c.name == "test.Foo!(true)") { return c; // c is the TypeInfo_Class that matches the given class name } ``` https://github.com/dlang/druntime/blob/master/src/object.d#L1661 Afterwards it calls the create function on the TypeInfo_Class which of course isn't "generic" by any means. This is where compile-time has its limits compared to runtime type creation, because templates only live during compile-time then it isn't really that easy to do something like this, where it would be trivial in other languages like C#.
Re: Parameters declared as the alias of a template won't accept the arguments of the same type.
On Monday, 2 May 2022 at 19:17:19 UTC, Stanislav Blinov wrote: On Monday, 2 May 2022 at 16:29:05 UTC, Loara wrote: Template deduction for aliased function parameter is a very tricky argument and it's not so simple to handle in certain cases. Consider for example this code: ```d template MyAlias(T){ alias MyAlias = int; } T simp(T)(MyAlias!T val){ return T.init; } int main(){ simp(3);//Impossible to deduce T Why? That's the issue. It is very possible to deduce T here. Compiler just isn't trying. The function takes an int. Doesn't take a rocket scientist to figure that one out. No, an alias is not a type and it'll be immediately substitutedwith the aliased symbol. You should use [typedefs](https://dlang.org/phobos/std_typecons.html#Typedef) in order to create a different type.
Re: Parameters declared as the alias of a template won't accept the arguments of the same type.
On Monday, 2 May 2022 at 17:21:53 UTC, JG wrote: On Monday, 2 May 2022 at 16:29:05 UTC, Loara wrote: On Sunday, 1 May 2022 at 03:57:12 UTC, Elfstone wrote: [...] Template deduction for aliased function parameter is a very tricky argument and it's not so simple to handle in certain cases. Consider for example this code: ```d template MyAlias(T){ alias MyAlias = int; } T simp(T)(MyAlias!T val){ return T.init; } int main(){ simp(3);//Impossible to deduce T simp( cast(MyAlias!string) 4);//Also invalid since MyAlias!string is exactly int simp!string(4);//Ok, no parameter deduction } ``` I don't really see what your example is trying to show. This also doesn't work, and in my mind should be equivalent: ```d T simp(T)(int val) { return T.init; } int main() { simp(3);//Impossible to deduce T } ``` Yeah I know, but I'm trying to show that allowing aliased templated function parameters will bring many bugs in user code, especially with aliases that alias another aliased declarations. I think using [typedefs](https://dlang.org/phobos/std_typecons.html#Typedef) and template constraints is simpler and make your code more readable too.
Re: How to get compatible symbol names and runtime typeid names for templated classes?
On Tuesday, 3 May 2022 at 09:42:45 UTC, cc wrote: Given a runtime typeid, how can I get the equivalent fullyQualifiedName without attempting to mangle the string myself manually? e.g. something I can pass to `Object.factory`. Actually, looking at this further, does Object.factory even support templates? I'm getting null returned from any attempt to instantiate a templated classname.
How to get compatible symbol names and runtime typeid names for templated classes?
This produces compatible strings between symbol and runtime type: ```d class Foo {} void main() { alias Foo F; writeln(fullyQualifiedName!F); auto f = new F; writeln(typeid(f).name); } ``` ``` test.Foo test.Foo ``` But if the class is a template, the strings different: ```d class Foo(bool b) {} void main() { alias Foo!true F; writeln(fullyQualifiedName!F); auto f = new F; writeln(typeid(f).name); } ``` ``` test.Foo!(true) test.Foo!true.Foo ``` Given a runtime typeid, how can I get the equivalent fullyQualifiedName without attempting to mangle the string myself manually? e.g. something I can pass to `Object.factory`.
Re: Parameters declared as the alias of a template won't accept the arguments of the same type.
On Tuesday, 3 May 2022 at 06:20:53 UTC, Elfstone wrote: Yeah, I understand some cases are impossible, and to be avoided. I believe your example is also impossible in C++, but it's better the compiler do its job when it's totally possible - needless to say, C++ compilers can deduce my _dot_. Constraints/Concepts are useful, but what's needed here is a literal _alias_. There's no ambiguity, no extra template parameters introduced in the declaration. I haven't read all of the posts in this thread, but D in general doesn't do proper type unification so template composition in D is not as useful as in C++. It is discussed here: https://forum.dlang.org/post/rt26mu$2c6q$1...@digitalmars.com As you see, someone will have to write a DIP to fix this bug, as the language authors don't consider it a bug, but an enhancement. I've never got around to do it myself, but if you or someone else write the DIP, then I would like to help out with the wording if needed.
Re: Parameters declared as the alias of a template won't accept the arguments of the same type.
On Monday, 2 May 2022 at 16:29:05 UTC, Loara wrote: On Sunday, 1 May 2022 at 03:57:12 UTC, Elfstone wrote: [...] Template deduction for aliased function parameter is a very tricky argument and it's not so simple to handle in certain cases. Consider for example this code: ```d template MyAlias(T){ alias MyAlias = int; } T simp(T)(MyAlias!T val){ return T.init; } int main(){ simp(3);//Impossible to deduce T simp( cast(MyAlias!string) 4);//Also invalid since MyAlias!string is exactly int simp!string(4);//Ok, no parameter deduction } ``` Instead to use aliases it's better (both in D and in C++) to use constraints/concepts. Yeah, I understand some cases are impossible, and to be avoided. I believe your example is also impossible in C++, but it's better the compiler do its job when it's totally possible - needless to say, C++ compilers can deduce my _dot_. Constraints/Concepts are useful, but what's needed here is a literal _alias_. There's no ambiguity, no extra template parameters introduced in the declaration.