www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Fact checking for my talk

reply Ethan Watson <gooberman gmail.com> writes:
So I fly to Cologne tomorrow morning, and will be presenting on 
Tuesday. Got my talk written, gave it a dry run at the office and 
got feedback on it. Seems to be in a good spot.

But before I go up and feature compare to other languages, it'll 
be a good idea to get my facts right.

There's three spots in my talk where I go through some D code, 
and then show a table indicating whether the features I used in 
those examples are available in other, trendier languages. In 
some cases, the features become available with after-market add 
ons. But I'm focusing exclusively on stuff you can get out of the 
box, ie write some code and compile it with a stock 
DMD/LDC/GDC/SDC install and it'll Just Work(TM).

So here's a dodgy table indicating the features I'm showing on 
the slides, and the languages that are most relevant to game 
developers - C# and Swift - with Rust thrown in since that's the 
new language everyone knows about.

If I've got something wrong with the out-of-the-box solution, 
please let me know. If there is something you can do with an 
add-on, also let me know since it will allow me to prepare for 
the inevitable audience questions saying "but you can do this 
with this etc etc"


                              |  Rust   |  Swift  |    C#   |
-----------------------------|---------+---------+---------|
     Template Constraints     |    Y    |    Y    |  where  | [1]
-----------------------------|---------+---------+---------|
   Template "if" Constraints  |  where  |  where  |  where  |
-----------------------------|---------+---------+---------|
         static if            |    N    |    N    |    N    |
-----------------------------|---------+---------+---------|
      Eponymous templates     |    N    |    N    |    N    |
-----------------------------|---------+---------+---------|
    Compile time reflection   |    N    |    N    |    N    |
-----------------------------|---------+---------+---------|
             CTFE             |    N    |    N    |    N    |
-----------------------------|---------+---------+---------|
    User defined attributes   |  Crates | Runtime |    Y    |
-----------------------------|---------+---------+---------|
    Deep function inspection  |    N    |    N    |    N    |
-----------------------------|---------+---------+---------|
            Mixins            |    N    |    N    |    N*   | [2]
-----------------------------|---------+---------+---------|

[1] Limited comparisons can be made with template where 
constraints
[2] Mixins in swift are essentially traits and protocol 
extentions, not like D mixins at all
Aug 13 2016
next sibling parent reply ag0aep6g <anonymous example.com> writes:
On 08/13/2016 02:47 PM, Ethan Watson wrote:
                              |  Rust   |  Swift  |    C#   |
 -----------------------------|---------+---------+---------|
     Template Constraints     |    Y    |    Y    |  where  | [1]
 -----------------------------|---------+---------+---------|
   Template "if" Constraints  |  where  |  where  |  where  |
What's a 'template "if" constraint'? Template constraints already use the `if` keyword. This is a template constraint: template Foo(T) if (is(T : int)) {/* ... */} Other than those, there are template specializations. Example: template Foo(T : int) {/* ... */}
Aug 13 2016
parent Ethan Watson <gooberman gmail.com> writes:
On Saturday, 13 August 2016 at 12:58:36 UTC, ag0aep6g wrote:
 What's a 'template "if" constraint'? Template constraints 
 already use the `if` keyword. This is a template constraint:

     template Foo(T) if (is(T : int)) {/* ... */}

 Other than those, there are template specializations. Example:

     template Foo(T : int) {/* ... */}
Bad naming on my part. I'll rename it. Although considering type deduction/parameter matching/specialisation is syntactically related, I'll find a better umbrella name for that.
Aug 13 2016
prev sibling next sibling parent reply Liam McSherry <mcsherry.liam gmail.com> writes:
On Saturday, 13 August 2016 at 12:47:40 UTC, Ethan Watson wrote:
                              |  Rust   |  Swift  |    C#   |
 -----------------------------|---------+---------+---------|
     Template Constraints     |    Y    |    Y    |  where  | [1]
 -----------------------------|---------+---------+---------|
   Template "if" Constraints  |  where  |  where  |  where  |
 -----------------------------|---------+---------+---------|
         static if            |    N    |    N    |    N    |
 -----------------------------|---------+---------+---------|
It might be something to note that C# doesn't have templates. Generics can only have type parameters (i.e. `int` or `string` not `5` or `Hello World`), and the `where` constraint is pretty restricted in what it can do: o Is T or is subclass of T/implements interface (class C<T> where T : U) o Default/parameterless constructor (class C<T> where T : new()) o Reference/value type checking (class C<T> where T : class/where T : struct) For "static if," C# also has a very limited conditional compilation system that is barely comparable. Symbols can be defined at compile time, but they can't have values and they can only be used with specific directives: --- #define X #if X doA(); #else doB(); #endif ---
Aug 13 2016
next sibling parent Ethan Watson <gooberman gmail.com> writes:
On Saturday, 13 August 2016 at 13:02:09 UTC, Liam McSherry wrote:
 For "static if," C# also has a very limited conditional 
 compilation system that is barely comparable.
This is covered in more detail in the talk itself when I compare static if to C style preprocessors. I would hope everyone in the room knows the C# preprocessor is limited compared to a C/C++ preprocessor. And if not, someone will either ask or Google it themselves after the event.
Aug 13 2016
prev sibling next sibling parent reply deadalnix <deadalnix gmail.com> writes:
On Saturday, 13 August 2016 at 13:02:09 UTC, Liam McSherry wrote:
 On Saturday, 13 August 2016 at 12:47:40 UTC, Ethan Watson wrote:
                              |  Rust   |  Swift  |    C#   |
 -----------------------------|---------+---------+---------|
     Template Constraints     |    Y    |    Y    |  where  | 
 [1]
 -----------------------------|---------+---------+---------|
   Template "if" Constraints  |  where  |  where  |  where  |
 -----------------------------|---------+---------+---------|
         static if            |    N    |    N    |    N    |
 -----------------------------|---------+---------+---------|
It might be something to note that C# doesn't have templates.
Not true. C# use generic (aka type erasure) for objects, but use template for value types. C# doesn't make the difference at the language level, but that is obvious from the fact that there is no way to do generic for value types. C# even does virtual dispatch on them, by storing a hashmap in the vtable and looking up implementation from typeinfos.
Aug 13 2016
parent reply Chris Wright <dhasenan gmail.com> writes:
On Sat, 13 Aug 2016 16:28:57 +0000, deadalnix wrote:
 C# use generic (aka type erasure) for objects
Incorrect: --- public class Foo {} var fooList = new List<Foo>(); var objectList = (List<object>)(object)fooList; --- This throws InvalidCastException. Which isn't possible with type erasure. The equivalent Java code will not throw an exception because, after type checking, List<T> is converted to List<Object>. That's the definition of type erasure. Similarly, you can inspect the methods on List<Foo> at runtime in C# and see that, for instance, the `Add` method takes a parameter of type Foo. And you can look at the type of `fooList` with reflection and see that it's List with generic parameter 0 set to Foo. That's stuff you can't do with type erasure. The code that .NET generates for a generic instantiation with class type is different from the code it generates for a generic instantiation for a struct simply because structs are not like classes.
Aug 13 2016
parent Lodovico Giaretta <lodovico giaretart.net> writes:
On Saturday, 13 August 2016 at 17:27:35 UTC, Chris Wright wrote:
 On Sat, 13 Aug 2016 16:28:57 +0000, deadalnix wrote:
 C# use generic (aka type erasure) for objects
Incorrect: --- public class Foo {} var fooList = new List<Foo>(); var objectList = (List<object>)(object)fooList; --- This throws InvalidCastException. Which isn't possible with type erasure. The equivalent Java code will not throw an exception because, after type checking, List<T> is converted to List<Object>. That's the definition of type erasure. Similarly, you can inspect the methods on List<Foo> at runtime in C# and see that, for instance, the `Add` method takes a parameter of type Foo. And you can look at the type of `fooList` with reflection and see that it's List with generic parameter 0 set to Foo. That's stuff you can't do with type erasure. The code that .NET generates for a generic instantiation with class type is different from the code it generates for a generic instantiation for a struct simply because structs are not like classes.
I guess what he meant is that there will be just one code generation, as all class types are just pointers. So on this side it behaves like Java (if we only talk about reference types). The difference is that the .NET IL retains complete type information for the variables, even if it dispatches to the same instantiation.
Aug 13 2016
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/13/2016 6:02 AM, Liam McSherry wrote:
 For "static if," C# also has a very limited conditional compilation system that
 is barely comparable. Symbols can be defined at compile time, but they can't
 have values and they can only be used with specific directives:
 ---
 #define X

 #if X
     doA();
 #else
     doB();
 #endif
 ---
That seems to correspond with D's 'version' construct.
Aug 13 2016
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 13/08/16 14:47, Ethan Watson wrote:
 So I fly to Cologne tomorrow morning, and will be presenting on Tuesday.
 Got my talk written, gave it a dry run at the office and got feedback on
 it. Seems to be in a good spot.

 But before I go up and feature compare to other languages, it'll be a
 good idea to get my facts right.

 -----------------------------|---------+---------+---------|
     Compile time reflection   |    N    |    N    |    N    |
 -----------------------------|---------+---------+---------|
              CTFE             |    N    |    N    |    N    |
 -----------------------------|---------+---------+---------|
It would be interesting to here what's the view of macros in Rust when it comes to CTFE and compile time reflection. Macros evaluate at compile time and to be usable they need to support compile time reflection. Or are macros consider something different?
 -----------------------------|---------+---------+---------|
     Deep function inspection  |    N    |    N    |    N    |
 -----------------------------|---------+---------+---------|
What is "Deep function inspection"? -- /Jacob Carlborg
Aug 13 2016
parent reply Ethan Watson <gooberman gmail.com> writes:
On Saturday, 13 August 2016 at 15:51:18 UTC, Jacob Carlborg wrote:
 What is "Deep function inspection"?
In the context of my talk, a collection of methods to inspect all function traits including parameter types and defaults etc. C++ can do type inspection. I believe Swift has something like Objective C does but I did not find concrete info on it. No idea about Rust.
Aug 13 2016
next sibling parent reply Chris Wright <dhasenan gmail.com> writes:
On Sat, 13 Aug 2016 16:19:08 +0000, Ethan Watson wrote:

 On Saturday, 13 August 2016 at 15:51:18 UTC, Jacob Carlborg wrote:
 What is "Deep function inspection"?
In the context of my talk, a collection of methods to inspect all function traits including parameter types and defaults etc. C++ can do type inspection. I believe Swift has something like Objective C does but I did not find concrete info on it. No idea about Rust.
C# can do this. Check System.Reflection.MethodInfo and System.Reflection.ParameterInfo. ParameterInfo has properties Attributes, CustomAttributes, ParameterType, and DefaultValue that you can inspect. (Attributes are for things like out and ref parameters; CustomAttributes are for [UserDefinedAttributes].)
Aug 13 2016
parent reply Ethan Watson <gooberman gmail.com> writes:
On Saturday, 13 August 2016 at 17:19:42 UTC, Chris Wright wrote:
 C# can do this. Check System.Reflection.MethodInfo and 
 System.Reflection.ParameterInfo.
Runtime only? I'll make the distinction on my slides.
Aug 13 2016
parent Chris Wright <dhasenan gmail.com> writes:
On Sat, 13 Aug 2016 17:21:37 +0000, Ethan Watson wrote:

 On Saturday, 13 August 2016 at 17:19:42 UTC, Chris Wright wrote:
 C# can do this. Check System.Reflection.MethodInfo and
 System.Reflection.ParameterInfo.
Runtime only? I'll make the distinction on my slides.
Runtime only, but you can generate code at runtime, albeit awkwardly.
Aug 13 2016
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/13/2016 9:19 AM, Ethan Watson wrote:
 I believe Swift has something like Objective C does but I did not find concrete
 info on it. No idea about Rust.
It's risky to compare with languages you aren't strongly familiar with. All it takes is one mistake and one audience member who knows more than you about it, and it can seriously derail and damage the entire presentation. I recommend sticking with describing the unique D features, and let the audience members who know other languages draw their own comparisons.
Aug 13 2016
parent reply Ethan Watson <gooberman gmail.com> writes:
On Saturday, 13 August 2016 at 19:34:42 UTC, Walter Bright wrote:
 It's risky to compare with languages you aren't strongly 
 familiar with. All it takes is one mistake and one audience 
 member who knows more than you about it, and it can seriously 
 derail and damage the entire presentation.

 I recommend sticking with describing the unique D features, and 
 let the audience members who know other languages draw their 
 own comparisons.
I do agree with this. But by the same token, the table highlights what actually are the unique D features. I make a point that the languages themselves are reasonable enough replacements for C++ in many circumstances, but that the things I do with D's compile time functionality aren't easily achievable in those languages. At this point, the only thing I still haven't found concrete information on is function inspection in Swift and Rust, which should be a mark against the languages if it's not easily Googlable.
Aug 15 2016
next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2016-08-16 08:13, Ethan Watson wrote:

 At this point, the only thing I still haven't found concrete information
 on is function inspection in Swift and Rust, which should be a mark
 against the languages if it's not easily Googlable.
For Objective-C it's possible to use the Objective-C runtime functions to access some of this information. Based on a method you can access the types of the arguments and the return type. Although this data is represented as strings, in a semi mangled format. All this should be accessible in Swift as well but will only (I assume) work for Swift methods that can be called from Objective-C. "Native" Swift methods support other features that are not accessible in Objective-C, like generics. -- /Jacob Carlborg
Aug 15 2016
parent Ethan Watson <gooberman gmail.com> writes:
On Tuesday, 16 August 2016 at 06:36:25 UTC, Jacob Carlborg wrote:
 On 2016-08-16 08:13, Ethan Watson wrote:

 For Objective-C it's possible to use the Objective-C runtime 
 functions to access some of this information. Based on a method 
 you can access the types of the arguments and the return type. 
 Although this data is represented as strings, in a semi mangled 
 format. All this should be accessible in Swift as well but will 
 only (I assume) work for Swift methods that can be called from 
 Objective-C. "Native" Swift methods support other features that 
 are not accessible in Objective-C, like generics.
Yeah, this is what I thought was possible with Swift. So thanks for that.
Aug 16 2016
prev sibling parent reply ZombineDev <petar.p.kirov gmail.com> writes:
On Tuesday, 16 August 2016 at 06:13:18 UTC, Ethan Watson wrote:
 [snip]

 At this point, the only thing I still haven't found concrete 
 information on is function inspection in Swift and Rust, which 
 should be a mark against the languages if it's not easily 
 Googlable.
From what I could find, definitely no other language from the list than C++ and D provides any sort of compile-time reflection. Between C#, Swift and Rust, C# has the most mature and fully-featured runtime reflection support. Almost every major .NET framework makes heavy use of it. I have even seen it casually used in combination with System.Reflection.Emit [1] for runtime codegen (for efficient DataBinding or FFI to native libraries, when P/Invoke is not enough). Because of the nature of CLR's JIT the difference between CT and RT is quite fuzzy. This even makes for some twisted form of `static if` [2.1] (look for the use of `if (typeof(T) == typeof(Int32))` in the code [2.2]). Though the actual code gen and optimization is treated like an implementation detail - I don't think it is guaranteed in any way. The only thing that I could find about Rust is that they didn't want to support any reflection beyond `typeid` [3] , because apparently that bloated binaries too much and such cost was too much for every project to pay. `typeid` is used by their `Any` trait [4] which basically is used for dynamic casting. From what I understand, you can't even tell at runtime if an object implements a trait. All you can do is use object.is::<T>() to check if the object is of some concrete type. Swift developers, on the other hand, explicitly state that they don't want to support any form compile-time metaprogramming: [5]. Ironically they make heavy use of it in their standard-library. However instead of writing the meta code in Swift, they use Python [6] for some weird variant of .NET's T4 preprocessor templates [7]. As for runtime reflection, as Jacob said, you can leverage the Objective-C heritage if your classes derive from `NSObject` [8]. Otherwise, due to the needs of things like XCode's Playground (which btw, is a poor imitation of Bret Victor's ideas [9]), Swift 2 also features some new runtime reflection capabilities [10] [11]. [1]: https://msdn.microsoft.com/en-us/library/system.reflection.emit(v=vs.110).aspx [2.1]: https://github.com/dotnet/corefx/blob/v1.0.0/src/System.Numerics.Vectors/src/System/Numerics/Vector.tt#L17 [2.2]: https://github.com/dotnet/corefx/blob/v1.0.0/src/System.Numerics.Vectors/src/System/Numerics/Vector.cs#L95 [3]: http://stackoverflow.com/questions/36416773/how-does-rust-implement-reflection [4]: https://github.com/rust-lang/rust/blob/master/src/libcore/any.rs [5]: https://github.com/apple/swift/blame/master/docs/Generics.rst#L85 [6]: https://github.com/apple/swift/blob/swift-DEVELOPMENT-SNAPSHOT-2016-08-15-a/stdlib/public/core/FloatingPoint.swift.gyb#L1485 [7]: https://msdn.microsoft.com/en-us/library/bb126445.aspx [8]: http://stackoverflow.com/a/24072677 [9]: http://worrydream.com/LearnableProgramming/ [10]: https://developer.apple.com/library/tvos/documentation/Swift/Reference/Swift_Mirror_Structure/index.html [11]: https://appventure.me/2015/10/24/swift-reflection-api-what-you-can-do/
Aug 16 2016
parent Jacob Carlborg <doob me.com> writes:
On 2016-08-16 17:08, ZombineDev wrote:

 Swift developers, on the other hand, explicitly state that they don't
 want to support any form compile-time metaprogramming: [5]. Ironically
 they make heavy use of it in their standard-library. However instead of
 writing the meta code in Swift, they use Python [6] for some weird
 variant of .NET's T4 preprocessor templates [7].
Hehe, looks a bit weird. Although they do have some form of language support that looks similar to the version statement in D. -- /Jacob Carlborg
Aug 16 2016
prev sibling next sibling parent Marc =?UTF-8?B?U2Now7x0eg==?= <schuetzm gmx.net> writes:
On Saturday, 13 August 2016 at 12:47:40 UTC, Ethan Watson wrote:

                              |  Rust   |  Swift  |    C#   |
 -----------------------------|---------+---------+---------|
     Template Constraints     |    Y    |    Y    |  where  | [1]
 -----------------------------|---------+---------+---------|
   Template "if" Constraints  |  where  |  where  |  where  |
 -----------------------------|---------+---------+---------|
         static if            |    N    |    N    |    N    |
 -----------------------------|---------+---------+---------|
      Eponymous templates     |    N    |    N    |    N    |
 -----------------------------|---------+---------+---------|
    Compile time reflection   |    N    |    N    |    N    |
 -----------------------------|---------+---------+---------|
             CTFE             |    N    |    N    |    N    |
 -----------------------------|---------+---------+---------|
    User defined attributes   |  Crates | Runtime |    Y    |
 -----------------------------|---------+---------+---------|
Hmm... does "Crates" mean that the feature is available as an optional package on crates.io? Otherwise I fail to see the connection between crates and UDAs...
    Deep function inspection  |    N    |    N    |    N    |
 -----------------------------|---------+---------+---------|
            Mixins            |    N    |    N    |    N*   | [2]
 -----------------------------|---------+---------+---------|
String mixins or template mixins?
Aug 13 2016
prev sibling next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/13/2016 5:47 AM, Ethan Watson wrote:
 [2] Mixins in swift are essentially traits and protocol extentions, not like D
 mixins at all
s/extentions/extensions/
Aug 13 2016
prev sibling parent reply ZombineDev <petar.p.kirov gmail.com> writes:
On Saturday, 13 August 2016 at 12:47:40 UTC, Ethan Watson wrote:
 So I fly to Cologne tomorrow morning, and will be presenting on 
 Tuesday. Got my talk written, gave it a dry run at the office 
 and got feedback on it. Seems to be in a good spot.

 But before I go up and feature compare to other languages, 
 it'll be a good idea to get my facts right.

 There's three spots in my talk where I go through some D code, 
 and then show a table indicating whether the features I used in 
 those examples are available in other, trendier languages. In 
 some cases, the features become available with after-market add 
 ons. But I'm focusing exclusively on stuff you can get out of 
 the box, ie write some code and compile it with a stock 
 DMD/LDC/GDC/SDC install and it'll Just Work(TM).

 So here's a dodgy table indicating the features I'm showing on 
 the slides, and the languages that are most relevant to game 
 developers - C# and Swift - with Rust thrown in since that's 
 the new language everyone knows about.

 If I've got something wrong with the out-of-the-box solution, 
 please let me know. If there is something you can do with an 
 add-on, also let me know since it will allow me to prepare for 
 the inevitable audience questions saying "but you can do this 
 with this etc etc"


                              |  Rust   |  Swift  |    C#   |
 -----------------------------|---------+---------+---------|
     Template Constraints     |    Y    |    Y    |  where  | [1]
 -----------------------------|---------+---------+---------|
   Template "if" Constraints  |  where  |  where  |  where  |
 -----------------------------|---------+---------+---------|
         static if            |    N    |    N    |    N    |
 -----------------------------|---------+---------+---------|
      Eponymous templates     |    N    |    N    |    N    |
 -----------------------------|---------+---------+---------|
    Compile time reflection   |    N    |    N    |    N    |
 -----------------------------|---------+---------+---------|
             CTFE             |    N    |    N    |    N    |
 -----------------------------|---------+---------+---------|
    User defined attributes   |  Crates | Runtime |    Y    |
 -----------------------------|---------+---------+---------|
    Deep function inspection  |    N    |    N    |    N    |
 -----------------------------|---------+---------+---------|
            Mixins            |    N    |    N    |    N*   | [2]
 -----------------------------|---------+---------+---------|

 [1] Limited comparisons can be made with template where 
 constraints
 [2] Mixins in swift are essentially traits and protocol 
 extentions, not like D mixins at all
         static if N
Rust does have an extremely limited form of static if - `#[cfg()]` [1] - similar to C#'s #if and D's `version ()` which (AFAIU [2]) can only test build-time constants. There's a cfg! macro [3] in the standard library which allows to evaluate (at CT) the expression for example in `if` statements, but it wont [4] delete the not-taken branch (so the code in both branches must be valid), which makes it quite useless. I found a `cfg_if!` macro in their libc FFI bindings [5], which it looks like it [6] can disable the not taken branch, but still, it's quite incapable compared to D's `static if`.
    User defined attributes
As per [7] currently you're not allowed to create your own attributes, only the Rust compiler defines them. From my understanding they're a syntax used for what `pragma`, `extern` and dub.json are used in D (in Rust packages (a.k.a crates) are built into the language). Rust attributes also cover many things for which usually the C/C++ __attribute__ extension is used. So I would say "N" on this one. Also note that in contrast with D, where attributes don't change the behavior of the attributed symbol, in Rust they're strictly used for controlling behavior.
    Eponymous templates      N
    Compile time reflection  N
Yeah, definitely no.
            Mixins N
             CTFE  N
I would say that Rust macros are the closest thing to string mixins, but are still light years away, because they can't be generated imperatively like you can in D with CTFE. OTOH, they're used in more places in their standard library, than mixins are used in Phobos, because of the lack of variadic templates, because in Rust you can't generalize over mutability, like you can in D with `inout` and also because of the stupidly designed trait system (e.g. see [9]). From my understanding of Rust macros, they're kind of like the AliasSeq algorithms in std.meta (because they're declarative), but instead of operating on sequences (e.g. template arguments lists) they operate on Rust's AST (e.g. statements and expressions). Actually I guess you can say that they're similar to D's template mixins, with the exception that template mixins can't mix expressions and statements into your code - Rust macros operate at the AST level, whereas D template mixin's are a bit higher-level, closer to the type system. | Rust | Swift | C# | D | C++ | --------------------|---------+---------+---------+--------+---------+ Compiler plugins | Y [8] | N | Roslyn | N | Clang | --------------------|---------+---------+---------+--------|---------+ However their compiler plugin systems looks quite fleshed-out [8] (at least compared to D's situation) so that's one metaprogramming area where definitely Rust has the lead. [1]: https://doc.rust-lang.org/book/conditional-compilation.html [2]: https://doc.rust-lang.org/reference.html#conditional-compilation [3]: https://doc.rust-lang.org/std/macro.cfg!.html [4]: https://users.rust-lang.org/t/cfg-macro-for-features/1337 [5]: https://github.com/rust-lang/libc/blob/0.2.15/src/macros.rs#L9 [6]: https://github.com/rust-lang/libc/blob/0.2.15/src/windows.rs#L10 [7]: https://doc.rust-lang.org/book/attributes.html [8]: https://doc.rust-lang.org/book/compiler-plugins.html [9]: https://github.com/rust-lang/rust/blob/master/src/libcore/slice.rs#L804
Aug 14 2016
next sibling parent reply Enamex <enamex+d outlook.com> writes:
On Sunday, 14 August 2016 at 18:05:12 UTC, ZombineDev wrote:
[...]
 OTOH, they're used in more places in their standard library, 
 than mixins are used in Phobos, because of the lack of variadic 
 templates, because in Rust you can't generalize over 
 mutability, like you can in D with `inout` and also because of 
 the stupidly designed trait system (e.g. see [9]).
I'm confused by your example. How exactly is Rust's trait system 'stupidly designed'? [...]
 From my understanding of Rust macros, they're kind of like the 
 AliasSeq algorithms in std.meta (because they're declarative), 
 but instead of operating on sequences (e.g. template arguments 
 lists) they operate on Rust's AST (e.g. statements and 
 expressions).
The AliasSeq algorithms are defined recursively for obvious reasons, but they rely on branching and a lot of obviously not declarative code in their definition. :? [...]
 [9]: 
 https://github.com/rust-lang/rust/blob/master/src/libcore/slice.rs#L804
Aug 14 2016
parent reply ZombineDev <petar.p.kirov gmail.com> writes:
On Sunday, 14 August 2016 at 18:17:58 UTC, Enamex wrote:
 On Sunday, 14 August 2016 at 18:05:12 UTC, ZombineDev wrote:
 [...]
 OTOH, they're used in more places in their standard library, 
 than mixins are used in Phobos, because of the lack of 
 variadic templates, because in Rust you can't generalize over 
 mutability, like you can in D with `inout` and also because of 
 the stupidly designed trait system (e.g. see [9]).
I'm confused by your example. How exactly is Rust's trait system 'stupidly designed'?
Ok, maybe it's a matter of taste and opinion, but I consider them to be bad design (idea-wise, not implementation-wise) because they're sort of the opposite of DbI and compile-time duck-typing. Maybe they fit nicely in Rust's world but they're definitely something I would want NOT to use. Concepts/traits are useless when you have DbI, because you can implement them in a library if you need dynamic dispatch (e.g. std.range.InputRangeObject, std.experimental.allocator.allocatorObject, std.typecons.wrap, etc.).
 [...]
 From my understanding of Rust macros, they're kind of like the 
 AliasSeq algorithms in std.meta (because they're declarative), 
 but instead of operating on sequences (e.g. template arguments 
 lists) they operate on Rust's AST (e.g. statements and 
 expressions).
The AliasSeq algorithms are defined recursively for obvious reasons, but they rely on branching and a lot of obviously not declarative code in their definition. :?
 and a lot of obviously not declarative code
Like what? They're definitely not imperative (e.g. in-place mutation is not possible), so I consider them to be declarative. The fact you can call any imperative D function at CT as the conditional expression is just a nice coincidence.
 [...]
 [9]: 
 https://github.com/rust-lang/rust/blob/master/src/libcore/slice.rs#L804
Aug 14 2016
parent reply Enamex <enamex+d outlook.com> writes:
On Sunday, 14 August 2016 at 18:57:14 UTC, ZombineDev wrote:
 Ok, maybe it's a matter of taste and opinion, but I consider 
 them to be bad design (idea-wise, not implementation-wise) 
 because they're sort of the opposite of DbI and compile-time 
 duck-typing. Maybe they fit nicely in Rust's world but they're 
 definitely something I would want NOT to use. Concepts/traits 
 are useless when you have DbI, because you can implement them 
 in a library if you need dynamic dispatch (e.g. 
 std.range.InputRangeObject, 
 std.experimental.allocator.allocatorObject, std.typecons.wrap, 
 etc.).
Can you demonstrate it through the example you linked to? And sorry, what's DbI again? :D
Aug 14 2016
parent reply ZombineDev <petar.p.kirov gmail.com> writes:
On Sunday, 14 August 2016 at 23:50:23 UTC, Enamex wrote:
 On Sunday, 14 August 2016 at 18:57:14 UTC, ZombineDev wrote:
 Ok, maybe it's a matter of taste and opinion, but I consider 
 them to be bad design (idea-wise, not implementation-wise) 
 because they're sort of the opposite of DbI and compile-time 
 duck-typing. Maybe they fit nicely in Rust's world but they're 
 definitely something I would want NOT to use. Concepts/traits 
 are useless when you have DbI, because you can implement them 
 in a library if you need dynamic dispatch (e.g. 
 std.range.InputRangeObject, 
 std.experimental.allocator.allocatorObject, std.typecons.wrap, 
 etc.).
Can you demonstrate it through the example you linked to? And sorry, what's DbI again? :D
Well, I guess it would hard for me to convince you if you don't know what Design by Introspection means. Truth be told, when I started learning D I also thought that concepts were the best idea thing ever (I was coming from C++ background, though I didn't have much experience with template metaprogramming), and by extension Rust's traits. It was perhaps after one or two years of using D, reviewing Phobos pull requests and watching Andrei's talk at DConf 2015 that I was finally convinced that concepts / traits are something not worth having. This is one those things that need time to sink in. Just like understanding that classic OOP is not the solution to all problems and that maybe functional programming is something worth looking into (i.e. it's not some academic nonsense).
Aug 14 2016
parent reply Chris Wright <dhasenan gmail.com> writes:
On Mon, 15 Aug 2016 06:43:11 +0000, ZombineDev wrote:
 Well, I guess it would hard for me to convince you if you don't know
 what Design by Introspection means.
Some years ago I was on #d on freenode and someone made a reference to high-order functions. I hadn't encountered the term, so I asked about it. The person answered that if I didn't know what it meant, I must not use high-order functions. In point of fact I was making moderate use of high-order functions at that time, but I hadn't heard that term for it. There is a difference between knowing how to do a thing and knowing a specific term for that thing. You still haven't defined the term "design by introspection". Some searching around says it's the pattern of: template Foo(T) { static if (is(typeof(T.bar)) { // preferred implementation takes advantage of T.bar } else { // alternate (also correct) implementation } } For instance, if T is an allocator and it has a `realloc` method, the preferred implementation, which uses `realloc`, will be chosen. Otherwise, the alternate implementation (which might use a linked list to avoid reallocating) will be chosen. The term was coined by Andrei, and he's had a couple talks about it, but nothing around here in the past few months. This pattern is handy for certain types of library code. It's not something that I have much use for.
Aug 15 2016
next sibling parent Seb <seb wilzba.ch> writes:
On Monday, 15 August 2016 at 14:40:14 UTC, Chris Wright wrote:
 You still haven't defined the term "design by introspection". 
 Some searching around says it's the pattern of:

 template Foo(T) {
   static if (is(typeof(T.bar)) {
     // preferred implementation takes advantage of T.bar
   } else {
     // alternate (also correct) implementation
   }
 }

 For instance, if T is an allocator and it has a `realloc` 
 method, the preferred implementation, which uses `realloc`, 
 will be chosen. Otherwise, the alternate implementation (which 
 might use a linked list to avoid reallocating) will be chosen.
There are is a ton of examples in Phobos, especially in std.algorithm or std.range: https://github.com/dlang/phobos/tree/master/std/algorithm https://github.com/dlang/phobos/tree/master/std/range The DTour also has a small Gem about it: http://tour.dlang.io/tour/en/gems/traits
Aug 15 2016
prev sibling next sibling parent reply Kagamin <spam here.lot> writes:
On Monday, 15 August 2016 at 14:40:14 UTC, Chris Wright wrote:
 You still haven't defined the term "design by introspection". 
 Some searching around says it's the pattern of:

 template Foo(T) {
   static if (is(typeof(T.bar)) {
     // preferred implementation takes advantage of T.bar
   } else {
     // alternate (also correct) implementation
   }
 }

 For instance, if T is an allocator and it has a `realloc` 
 method, the preferred implementation, which uses `realloc`, 
 will be chosen. Otherwise, the alternate implementation (which 
 might use a linked list to avoid reallocating) will be chosen.
Strategy pattern at compile time.
Aug 16 2016
parent Chris Wright <dhasenan gmail.com> writes:
On Tue, 16 Aug 2016 10:24:38 +0000, Kagamin wrote:

 On Monday, 15 August 2016 at 14:40:14 UTC, Chris Wright wrote:
 You still haven't defined the term "design by introspection". Some
 searching around says it's the pattern of:

 template Foo(T) {
   static if (is(typeof(T.bar)) {
     // preferred implementation takes advantage of T.bar
   } else {
     // alternate (also correct) implementation
   }
 }

 For instance, if T is an allocator and it has a `realloc` method, the
 preferred implementation, which uses `realloc`, will be chosen.
 Otherwise, the alternate implementation (which might use a linked list
 to avoid reallocating) will be chosen.
Strategy pattern at compile time.
Chosen by type introspection, specifically. I rarely need to implement the strategy pattern, and when I do I want to choose the strategy at runtime. But I see how it's useful in Phobos. I don't think it's the sort of feature that will strongly drive adoption and make other languages jealous, but it's built in an obvious way on top of general-purpose language features, and the fact that these features are available and as powerful as they are is awesome.
Aug 16 2016
prev sibling parent ZombineDev <petar.p.kirov gmail.com> writes:
On Monday, 15 August 2016 at 14:40:14 UTC, Chris Wright wrote:
 On Mon, 15 Aug 2016 06:43:11 +0000, ZombineDev wrote:
 Well, I guess it would hard for me to convince you if you 
 don't know what Design by Introspection means.
Some years ago I was on #d on freenode and someone made a reference to high-order functions. I hadn't encountered the term, so I asked about it. The person answered that if I didn't know what it meant, I must not use high-order functions. In point of fact I was making moderate use of high-order functions at that time, but I hadn't heard that term for it. There is a difference between knowing how to do a thing and knowing a specific term for that thing.
Sorry, I didn't mean my post to sound that way. From my experience of trying to explain DbI to a couple of friends, it's a hard to appreciate the paradigm if you're not already using it casually, and so it would be even harder for me to make a case for why it makes C++ concepts / Rust traits much less useful than they're advertised to be. The classic example would be walkLength [1]. However that example does not make a good case because it could also be implemented with overloading or dynamic casts (albeit at the cost of inflexibility and/or runtime pessimization) in other languages like C++ and C#. Personally, I really like things like Seb's recent work on attribute propagation for std.experimental.allocator.make and makeArray [2][3][4], but I'm not sure if that's an example a beginner would appreciate. [1]: https://github.com/dlang/phobos/blob/v2.071.2-b2/std/range/primitives.d#L1577 [2]: https://github.com/dlang/phobos/pull/4680/files [3]: https://github.com/dlang/phobos/pull/4682/files [4]: https://github.com/dlang/phobos/pull/4683/files
Aug 16 2016
prev sibling parent Ethan Watson <gooberman gmail.com> writes:
On Sunday, 14 August 2016 at 18:05:12 UTC, ZombineDev wrote:
 Rust stugg
Exactly what I was after, thanks.
Aug 15 2016