Re: Mix struct types in the same array

2019-12-20 Thread Laeeth Isharc via Digitalmars-d-learn

On Wednesday, 18 December 2019 at 22:17:21 UTC, tirithen wrote:
On Wednesday, 18 December 2019 at 22:11:10 UTC, Sebastiaan 
Koppe wrote:


If you know all types up front you can use the Sumtype library 
on code.dlang.org


Thanks, it's a good starting point, the best would be if I only 
needed to define that the struct would implement void 
applyTo(ref User user) so that could be run in the loop to 
update the User entity.


But I'll try the Sumtype library, that takes me forward, thanks 
for the answer!


https://github.com/atilaneves/concepts

interface IFoo {
int foo(int i, string s) @safe;
double lefoo(string s) @safe;
}

@implements!(Foo, IFoo)
struct Foo {
int foo(int i, string s) @safe { return 0; }
double lefoo(string s) @safe { return 0; }
}

// doesn't compile
/*
@implements!(Oops, IFoo)
struct Oops {}
*/


Re: Mix struct types in the same array

2019-12-20 Thread tirithen via Digitalmars-d-learn

On Thursday, 19 December 2019 at 21:26:51 UTC, Paul Backus wrote:


The reason this doesn't work is that interface methods are 
virtual, and virtual methods can't be templates. [1] If you 
want to have multiple kinds of entities, one option is to 
create an Entity interface and EntityAdapter(T) class using the 
same technique as above, and have your applyTo method accept an 
Entity as its argument. You can see an example of what that 
would look like at the following link:


https://gist.github.com/pbackus/f61734804a627d379c7916f783ea7725#file-oop_version-d

Another option is to forget about classes and interfaces and do 
everything with templates, using a library like sumtype [2]. 
Here's a link to an example of what that would look like:


https://gist.github.com/pbackus/f61734804a627d379c7916f783ea7725#file-template_version-d


Thanks for a good explanation around virtual methods and 
templates as well as examples! Now I have plenty of good examples 
to play around with. :)


Re: Mix struct types in the same array

2019-12-19 Thread Paul Backus via Digitalmars-d-learn

On Thursday, 19 December 2019 at 18:21:32 UTC, tirithen wrote:
On Thursday, 19 December 2019 at 00:00:56 UTC, Paul Backus 
wrote:


interface Action
{
void applyTo(ref User); <-- change to applyTo(T)(ref T)
}

class ActionAdapter(T) : Action
{
T payload;

this(T payload)
{
this.payload = payload;
}

override void applyTo(ref User user) <-- change to 
applyTo(U)(ref U entity)

{
payload.applyTo(user);
}
}


Is there a way I can make the example a bit more generic even 
by replacing the User type with a template. I tried:


applyTo(ref User); <-- applyTo(T)(ref T)
applyTo(ref User user) <-- applyTo(U)(ref U entity)

It compiled but crashed with:

Linking...
/usr/bin/ld: 
.dub/build/application-debug-linux.posix-x86_64-dmd_2089-4CFAD9B3CA5E5532C5E0608F9332C781/tryit.o: in function `_Dmain':
.tryit/source/app.d:55: undefined reference to 
`_D5plant5tryit3app5Event__T7applyToTSQBjQBgQBd4UserZQzMFKQvZv'

collect2: fel: ld returnerade avslutningsstatus 1

I'm still a bit new to this language so need to practice 
templates more, but I find D overall nice.


The reason this doesn't work is that interface methods are 
virtual, and virtual methods can't be templates. [1] If you want 
to have multiple kinds of entities, one option is to create an 
Entity interface and EntityAdapter(T) class using the same 
technique as above, and have your applyTo method accept an Entity 
as its argument. You can see an example of what that would look 
like at the following link:


https://gist.github.com/pbackus/f61734804a627d379c7916f783ea7725#file-oop_version-d

Another option is to forget about classes and interfaces and do 
everything with templates, using a library like sumtype [2]. 
Here's a link to an example of what that would look like:


https://gist.github.com/pbackus/f61734804a627d379c7916f783ea7725#file-template_version-d

Advantages of the interface + adapter version:
  + Can easily add new Actions and Entities, without changing 
existing code

  + Method dispatch is handled automatically by the compiler

Advantages of sumtype + templates version:
  + No need to allocate adapter objects on the heap

[1] https://dlang.org/spec/function.html#virtual-functions
[2] https://code.dlang.org/packages/sumtype


Re: Mix struct types in the same array

2019-12-19 Thread tirithen via Digitalmars-d-learn

On Thursday, 19 December 2019 at 00:00:56 UTC, Paul Backus wrote:


interface Action
{
void applyTo(ref User); <-- change to applyTo(T)(ref T)
}

class ActionAdapter(T) : Action
{
T payload;

this(T payload)
{
this.payload = payload;
}

override void applyTo(ref User user) <-- change to 
applyTo(U)(ref U entity)

{
payload.applyTo(user);
}
}


Is there a way I can make the example a bit more generic even by 
replacing the User type with a template. I tried:


applyTo(ref User); <-- applyTo(T)(ref T)
applyTo(ref User user) <-- applyTo(U)(ref U entity)

It compiled but crashed with:

Linking...
/usr/bin/ld: 
.dub/build/application-debug-linux.posix-x86_64-dmd_2089-4CFAD9B3CA5E5532C5E0608F9332C781/tryit.o: in function `_Dmain':
.tryit/source/app.d:55: undefined reference to 
`_D5plant5tryit3app5Event__T7applyToTSQBjQBgQBd4UserZQzMFKQvZv'

collect2: fel: ld returnerade avslutningsstatus 1

I'm still a bit new to this language so need to practice 
templates more, but I find D overall nice.


Re: Mix struct types in the same array

2019-12-19 Thread tirithen via Digitalmars-d-learn

On Thursday, 19 December 2019 at 00:00:56 UTC, Paul Backus wrote:
If all of the structs need to implement a particular method (or 
set of methods), you can use an interface and a templated 
adapter class to give them a common type. Here's a simple 
example:


Thank you for the example that looks like a wonderful example, 
I'll try it out. I like that the structs then can be declared 
when the array is constructed.


Re: Mix struct types in the same array

2019-12-18 Thread Paul Backus via Digitalmars-d-learn

On Wednesday, 18 December 2019 at 22:17:21 UTC, tirithen wrote:
On Wednesday, 18 December 2019 at 22:11:10 UTC, Sebastiaan 
Koppe wrote:


If you know all types up front you can use the Sumtype library 
on code.dlang.org


Thanks, it's a good starting point, the best would be if I only 
needed to define that the struct would implement void 
applyTo(ref User user) so that could be run in the loop to 
update the User entity.


If all of the structs need to implement a particular method (or 
set of methods), you can use an interface and a templated adapter 
class to give them a common type. Here's a simple example:


import std.stdio: writeln;

struct User
{
string name;
}

interface Action
{
void applyTo(ref User);
}

class ActionAdapter(T) : Action
{
T payload;

this(T payload)
{
this.payload = payload;
}

override void applyTo(ref User user)
{
payload.applyTo(user);
}
}

Action action(T)(T payload)
{
return new ActionAdapter!T(payload);
}

struct SayHello
{
void applyTo(ref User user)
{
writeln("Hello, ", user.name, ".");
}
}

struct SayGoodbye
{
void applyTo(ref User user)
{
writeln("Goodbye, ", user.name, ".");
}
}

void main()
{
Action[] actions = [action(SayHello()), action(SayGoodbye())];
auto user = User("Joe Schmoe");

foreach (action; actions)
action.applyTo(user);
}


Re: Mix struct types in the same array

2019-12-18 Thread tirithen via Digitalmars-d-learn
On Wednesday, 18 December 2019 at 22:11:10 UTC, Sebastiaan Koppe 
wrote:


If you know all types up front you can use the Sumtype library 
on code.dlang.org


Thanks, it's a good starting point, the best would be if I only 
needed to define that the struct would implement void applyTo(ref 
User user) so that could be run in the loop to update the User 
entity.


But I'll try the Sumtype library, that takes me forward, thanks 
for the answer!


Re: Mix struct types in the same array

2019-12-18 Thread Sebastiaan Koppe via Digitalmars-d-learn

On Wednesday, 18 December 2019 at 22:00:20 UTC, tirithen wrote:
I want to have a array/list/queue of instances of various 
struct types that represent events. How can I achieve that? 
With classes I would have interfaces I guess, but I want to use 
structs if possible as they seem less complex (and faster?).


Can I wrap each struct with in another struct called something 
like Entry that in turn can contain the event struct some how, 
or will that just move the problem?


If you know all types up front you can use the Sumtype library on 
code.dlang.org


Mix struct types in the same array

2019-12-18 Thread tirithen via Digitalmars-d-learn
I want to have a array/list/queue of instances of various struct 
types that represent events. How can I achieve that? With classes 
I would have interfaces I guess, but I want to use structs if 
possible as they seem less complex (and faster?).


Can I wrap each struct with in another struct called something 
like Entry that in turn can contain the event struct some how, or 
will that just move the problem?


import std.stdio;

struct User {
string username;
string email;
string unverifiedEmail;
string password;
}

struct UserCreate {
string username;
string email;

void applyTo(ref User user) {
user.username = this.username;
user.unverifiedEmail = this.email;
}
}

struct UserChangePassword {
string password;

void applyTo(ref User user) {
user.password = this.password;
}
}

// Not usable for structs
interface Event {
void applyTo(T)(ref T entity);
}

void main() {
// How can I create an array with mixed structs?
Event[] events;

events ~= UserCreate("hej", "h...@example.com");
events ~= UserChangePassword("hased1234");

User user;
foreach (event; events) {
event.applyTo(user);
}

writeln(user);
}