Jump to page: 1 2
Thread overview
How to make Rust trait like feature in dlang ?
Jun 16, 2019
lili
Jun 16, 2019
Alex
Jun 17, 2019
Newbie2019
Jun 17, 2019
bauss
Jun 17, 2019
Alex
Jun 17, 2019
Mike Franklin
Jun 17, 2019
lili
Jun 17, 2019
Mike Franklin
Jun 18, 2019
James Blachly
Jun 16, 2019
Jacob Carlborg
Jun 17, 2019
Guillaume Piolat
Jun 17, 2019
lili
Jun 17, 2019
XavierAP
Jun 17, 2019
lili
Jun 18, 2019
Atila Neves
June 16, 2019
Hi, guys:
   I really like Rust trait feature. Use it can implement duck-type simple.
   base on inherited OO is complex and hard, because you need to design inherited tree well.
   and this is not easy. In real word need runtime polymorphic is uncommon. lots of is just need compile time polymorphic.

for example: design a network socket lib you need to implement TCP,UDP,Unix socket and these
sockets have need implement send, recv function.

interface SocketLike {
   int send(ubyte[] data, uint32 len);
   int recv(ubyte[] buff, uint32 len);
}

struct TcpSocket : SocketLike {...} // in dlang struct can not allows to inherited interface
struct UdpSocket : SocketLike {...}
struct UnixSocket : SocketLike {...}

function UseSocketLike(SocketLike socket)
{
   socket.recv()
    ....
}


I not need runtime polymorphic, just need compiler check real argument is SocketLike type.
How do this, can dlang support conception like feature.


June 16, 2019
On Sunday, 16 June 2019 at 15:56:41 UTC, lili wrote:
> Hi, guys:
>    I really like Rust trait feature. Use it can implement duck-type simple.
>    base on inherited OO is complex and hard, because you need to design inherited tree well.
>    and this is not easy. In real word need runtime polymorphic is uncommon. lots of is just need compile time polymorphic.
>
> for example: design a network socket lib you need to implement TCP,UDP,Unix socket and these
> sockets have need implement send, recv function.
>
> interface SocketLike {
>    int send(ubyte[] data, uint32 len);
>    int recv(ubyte[] buff, uint32 len);
> }
>
> struct TcpSocket : SocketLike {...} // in dlang struct can not allows to inherited interface
> struct UdpSocket : SocketLike {...}
> struct UnixSocket : SocketLike {...}
>
> function UseSocketLike(SocketLike socket)
> {
>    socket.recv()
>     ....
> }
>
>
> I not need runtime polymorphic, just need compiler check real argument is SocketLike type.
> How do this, can dlang support conception like feature.

Beyond the fact, that such questions should be placed in the learn forum section, you can achieve such checks via templating the function and usage of template constraints.

https://dlang.org/spec/template.html#template_constraints

For example,
´´´
import std;

enum bool isSocketLike(T) =
    is(ReturnType!((T r) => r.send((ubyte[]).init, uint.init)) == int)
    && is(ReturnType!((T r) => r.recv((ubyte[]).init, uint.init)) == int);

void main()
{
    static assert(isSocketLike!T);
    static assert(!isSocketLike!F);
    UseSocketLike(T.init);
    static assert(!__traits(compiles, UseSocketLike(F.init)));
}

struct T
{
    int send(ubyte[] data, uint l){return 0;}
    int recv(ubyte[] buff, uint l){return 0;}
}

struct F{}

auto UseSocketLike(T)(T socket) if(isSocketLike!T)
{
    // ... and so on ...
}
´´´
June 16, 2019
On 2019-06-16 17:56, lili wrote:
> Hi, guys:
>     I really like Rust trait feature. Use it can implement duck-type simple.
>     base on inherited OO is complex and hard, because you need to design inherited tree well.
>     and this is not easy. In real word need runtime polymorphic is uncommon. lots of is just need compile time polymorphic.
> 
> for example: design a network socket lib you need to implement TCP,UDP,Unix socket and these
> sockets have need implement send, recv function.
> 
> interface SocketLike {
>     int send(ubyte[] data, uint32 len);
>     int recv(ubyte[] buff, uint32 len);
> }
> 
> struct TcpSocket : SocketLike {...} // in dlang struct can not allows to inherited interface
> struct UdpSocket : SocketLike {...}
> struct UnixSocket : SocketLike {...}
> 
> function UseSocketLike(SocketLike socket)
> {
>     socket.recv()
>      ....
> }
> 
> 
> I not need runtime polymorphic, just need compiler check real argument is SocketLike type.
> How do this, can dlang support conception like feature.

Have a look at how Mecca implements socket addresses [1].

[1] https://github.com/weka-io/mecca/blob/b36254e205ff8520effaa9ccc8bf74d73a28c639/src/mecca/lib/net.d#L538-L545


-- 
/Jacob Carlborg
June 17, 2019
On Sunday, 16 June 2019 at 19:13:05 UTC, Alex wrote:
>
> Beyond the fact, that such questions should be placed in the learn forum section, you can achieve such checks via templating the function and usage of template constraints.
>
> https://dlang.org/spec/template.html#template_constraints
>
> For example,
> ´´´
> import std;
>
> enum bool isSocketLike(T) =
>     is(ReturnType!((T r) => r.send((ubyte[]).init, uint.init)) == int)
>     && is(ReturnType!((T r) => r.recv((ubyte[]).init, uint.init)) == int);
>
> void main()
> {
>     static assert(isSocketLike!T);
>     static assert(!isSocketLike!F);
>     UseSocketLike(T.init);
>     static assert(!__traits(compiles, UseSocketLike(F.init)));
> }
>
> struct T
> {
>     int send(ubyte[] data, uint l){return 0;}
>     int recv(ubyte[] buff, uint l){return 0;}
> }
>
> struct F{}
>
> auto UseSocketLike(T)(T socket) if(isSocketLike!T)
> {
>     // ... and so on ...
> }
> ´´´

D can do it, but much less elegant. compare to Rust, d is like granny language.



June 17, 2019
On Monday, 17 June 2019 at 04:25:26 UTC, Newbie2019 wrote:
> On Sunday, 16 June 2019 at 19:13:05 UTC, Alex wrote:
>>
>> Beyond the fact, that such questions should be placed in the learn forum section, you can achieve such checks via templating the function and usage of template constraints.
>>
>> https://dlang.org/spec/template.html#template_constraints
>>
>> For example,
>> ´´´
>> import std;
>>
>> enum bool isSocketLike(T) =
>>     is(ReturnType!((T r) => r.send((ubyte[]).init, uint.init)) == int)
>>     && is(ReturnType!((T r) => r.recv((ubyte[]).init, uint.init)) == int);
>>
>> void main()
>> {
>>     static assert(isSocketLike!T);
>>     static assert(!isSocketLike!F);
>>     UseSocketLike(T.init);
>>     static assert(!__traits(compiles, UseSocketLike(F.init)));
>> }
>>
>> struct T
>> {
>>     int send(ubyte[] data, uint l){return 0;}
>>     int recv(ubyte[] buff, uint l){return 0;}
>> }
>>
>> struct F{}
>>
>> auto UseSocketLike(T)(T socket) if(isSocketLike!T)
>> {
>>     // ... and so on ...
>> }
>> ´´´
>
> D can do it, but much less elegant.

Maybe that's because they are not supposed to be implemented like that in D.

Surprise, surprise.

> compare to Rust, d is like granny language.

Based on what merit?
June 17, 2019
On Monday, 17 June 2019 at 04:25:26 UTC, Newbie2019 wrote:
> On Sunday, 16 June 2019 at 19:13:05 UTC, Alex wrote:
>>
>> Beyond the fact, that such questions should be placed in the learn forum section, you can achieve such checks via templating the function and usage of template constraints.
>>
>> https://dlang.org/spec/template.html#template_constraints
>>
>> For example,
>> ´´´
>> import std;
>>
>> enum bool isSocketLike(T) =
>>     is(ReturnType!((T r) => r.send((ubyte[]).init, uint.init)) == int)
>>     && is(ReturnType!((T r) => r.recv((ubyte[]).init, uint.init)) == int);
>>
>> void main()
>> {
>>     static assert(isSocketLike!T);
>>     static assert(!isSocketLike!F);
>>     UseSocketLike(T.init);
>>     static assert(!__traits(compiles, UseSocketLike(F.init)));
>> }
>>
>> struct T
>> {
>>     int send(ubyte[] data, uint l){return 0;}
>>     int recv(ubyte[] buff, uint l){return 0;}
>> }
>>
>> struct F{}
>>
>> auto UseSocketLike(T)(T socket) if(isSocketLike!T)
>> {
>>     // ... and so on ...
>> }
>> ´´´
>
> D can do it, but much less elegant. compare to Rust, d is like granny language.

I don't get your point.

If you want a socket implementation, use (or use as an inspiration) an existent library, as Jacob mentioned.

If you want some static checks of your code while developing, you could let away  half of the code I showed. The compiler will check all interface usages anyway.
June 17, 2019
On Sunday, 16 June 2019 at 15:56:41 UTC, lili wrote:
> How do this, can dlang support conception like feature.

Not only D has static polymorphism, but it does so with open capabilities / "DbI" / duck-typing-at-compile-time.

A real eye opener is this talk: https://www.youtube.com/watch?v=LIb3L4vKZ7U

Why do you think C++ took "static if"?
June 17, 2019
On Monday, 17 June 2019 at 09:23:35 UTC, Guillaume Piolat wrote:
> On Sunday, 16 June 2019 at 15:56:41 UTC, lili wrote:
>> How do this, can dlang support conception like feature.
>
> Not only D has static polymorphism, but it does so with open capabilities / "DbI" / duck-typing-at-compile-time.
>
> A real eye opener is this talk: https://www.youtube.com/watch?v=LIb3L4vKZ7U
>
> Why do you think C++ took "static if"?

Can't get your point. think what? C++ not support conception now.
D not yet. But conception is really powerful. So is dlang will support it.
for example: struct allow inherited interface, implement conception.
June 17, 2019
On Monday, 17 June 2019 at 04:25:26 UTC, Newbie2019 wrote:

> D can do it, but much less elegant. compare to Rust, d is like granny language.

Actually, D doesn't require all of the boilerplate to set up the interface and the implementation checking.  You just type it up because the compiler will tell you when something's not right.

```
import std.stdio;

struct TcpSocket
{
    int send(ubyte[] data, int len) { writeln("TcpSocket send"); return len; }
    int recv(ubyte[] buff, int len) { writeln("TcpSocket recv"); return len; }
}

struct UdpSocket
{
    int send(ubyte[] data, int len) { writeln("UdpSocket send"); return len; }
    int recv(ubyte[] buff, int len) { writeln("UdpSocket recv"); return len; }
}

struct UnixSocket
{
    int send(ubyte[] data, int len) { writeln("UdpSocket send"); return len; }
    int recv(ubyte[] buff, int len) { writeln("UdpSocket recv"); return len; }
}

struct NotASocket { }

void Use(T)(T socket)
{
    socket.send([], 0);
    socket.recv([], 0);
}

void main()
{
    TcpSocket socket;
    socket.Use();   // Works out of the box without any interface boilerplate

    NotASocket noSocket;
    noSocket.Use(); // Error: no property `send`/`recv` for type `NotASocket`
}
```
https://run.dlang.io/is/FpfkS6

I didn't even have to create an interface or implement one, yet the compiler knew what to do.

If you really wanted to do the interface boilerplate like Rust, that's also possible in D, but unnecessary IMO.  You could also use classes w/ interfaces, something Rust doesn't even have.

So in this situation, D gives you everything Rust has and more with less boilerplate.

Mike
June 17, 2019
On Monday, 17 June 2019 at 11:26:21 UTC, Mike Franklin wrote:
> On Monday, 17 June 2019 at 04:25:26 UTC, Newbie2019 wrote:
>
>> D can do it, but much less elegant. compare to Rust, d is like granny language.
>
> Actually, D doesn't require all of the boilerplate to set up the interface and the implementation checking.  You just type it up because the compiler will tell you when something's not right.
>
> ```
> import std.stdio;
>
> struct TcpSocket
> {
>     int send(ubyte[] data, int len) { writeln("TcpSocket send"); return len; }
>     int recv(ubyte[] buff, int len) { writeln("TcpSocket recv"); return len; }
> }
>
> struct UdpSocket
> {
>     int send(ubyte[] data, int len) { writeln("UdpSocket send"); return len; }
>     int recv(ubyte[] buff, int len) { writeln("UdpSocket recv"); return len; }
> }
>
> struct UnixSocket
> {
>     int send(ubyte[] data, int len) { writeln("UdpSocket send"); return len; }
>     int recv(ubyte[] buff, int len) { writeln("UdpSocket recv"); return len; }
> }
>
> struct NotASocket { }
>
> void Use(T)(T socket)
> {
>     socket.send([], 0);
>     socket.recv([], 0);
> }
>
> void main()
> {
>     TcpSocket socket;
>     socket.Use();   // Works out of the box without any interface boilerplate
>
>     NotASocket noSocket;
>     noSocket.Use(); // Error: no property `send`/`recv` for type `NotASocket`
> }
> ```
> https://run.dlang.io/is/FpfkS6
>
> I didn't even have to create an interface or implement one, yet the compiler knew what to do.
>
> If you really wanted to do the interface boilerplate like Rust, that's also possible in D, but unnecessary IMO.  You could also use classes w/ interfaces, something Rust doesn't even have.
>
> So in this situation, D gives you everything Rust has and more with less boilerplate.
>
> Mike

Yes, It's ok. but this did not represent to an conception under code.
I want to explicitly represent this is a SocketLike cenception.
because i want conception oriented programming not type oriented, this is more powerful in GP.
now I find a way that is use mixin template.
```
mixin template SocketLike {
   int send(ubyte[] data, int len);
   int recv(ubyte[] buff, int len);
}

struct TcpSocket {
   mixin SocketLike;
   //implement SocketLike behavior
   int send(ubyte[] data, int len) { writeln("TcpSocket send"); return len; }
   int recv(ubyte[] buff, int len) { writeln("TcpSocket recv"); return len; }
}

struct UdpSocket {
   mixin SocketLike;
   //implement SocketLike behavior
   int send(ubyte[] data, int len) { writeln("TcpSocket send"); return len; }
   int recv(ubyte[] buff, int len) { writeln("TcpSocket recv"); return len; }
}
```
this not perfect not this is already abstract an SocketLike conception.
« First   ‹ Prev
1 2