Re: How to use destroy and free.

2022-05-03 Thread forkit via Digitalmars-d-learn

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.

2022-05-03 Thread Mike Parker via Digitalmars-d-learn

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.

2022-05-03 Thread forkit via Digitalmars-d-learn

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.

2022-05-03 Thread Mike Parker via Digitalmars-d-learn

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.

2022-05-03 Thread Ola Fosheim Grøstad via Digitalmars-d-learn

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

2022-05-03 Thread user1234 via Digitalmars-d-learn

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

2022-05-03 Thread jmh530 via Digitalmars-d-learn

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

2022-05-03 Thread Dennis via Digitalmars-d-learn

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

2022-05-03 Thread Anonymouse via Digitalmars-d-learn

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

2022-05-03 Thread jmh530 via Digitalmars-d-learn
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?

2022-05-03 Thread H. S. Teoh via Digitalmars-d-learn
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?

2022-05-03 Thread cc via Digitalmars-d-learn

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

2022-05-03 Thread JG via Digitalmars-d-learn

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?

2022-05-03 Thread H. S. Teoh via Digitalmars-d-learn
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?

2022-05-03 Thread cc via Digitalmars-d-learn

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?

2022-05-03 Thread Adam D Ruppe via Digitalmars-d-learn

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?

2022-05-03 Thread H. S. Teoh via Digitalmars-d-learn
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.

2022-05-03 Thread Tejas via Digitalmars-d-learn

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?

2022-05-03 Thread cc via Digitalmars-d-learn

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.

2022-05-03 Thread Ali Çehreli via Digitalmars-d-learn

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?

2022-05-03 Thread Arafel via Digitalmars-d-learn

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.

2022-05-03 Thread Ali Çehreli via Digitalmars-d-learn

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.

2022-05-03 Thread H. S. Teoh via Digitalmars-d-learn
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?

2022-05-03 Thread H. S. Teoh via Digitalmars-d-learn
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.

2022-05-03 Thread Alain De Vos via Digitalmars-d-learn
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?

2022-05-03 Thread Adam D Ruppe via Digitalmars-d-learn

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?

2022-05-03 Thread Arafel via Digitalmars-d-learn

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?

2022-05-03 Thread Adam D Ruppe via Digitalmars-d-learn

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.

2022-05-03 Thread Mike Parker via Digitalmars-d-learn

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?

2022-05-03 Thread Arafel via Digitalmars-d-learn

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?

2022-05-03 Thread cc via Digitalmars-d-learn

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.

2022-05-03 Thread Alain De Vos via Digitalmars-d-learn
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?

2022-05-03 Thread Adam D Ruppe via Digitalmars-d-learn

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?

2022-05-03 Thread Arafel via Digitalmars-d-learn

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?

2022-05-03 Thread bauss via Digitalmars-d-learn

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.

2022-05-03 Thread Loara via Digitalmars-d-learn

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.

2022-05-03 Thread Loara via Digitalmars-d-learn

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?

2022-05-03 Thread cc via Digitalmars-d-learn

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?

2022-05-03 Thread cc via Digitalmars-d-learn

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.

2022-05-03 Thread Ola Fosheim Grøstad via Digitalmars-d-learn

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.

2022-05-03 Thread Elfstone via Digitalmars-d-learn

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.