Last active
January 23, 2018 19:13
-
-
Save ErichDonGubler/b9bb2c17cbd95157e39a517c068e22ab to your computer and use it in GitHub Desktop.
Response to "Methods and UFCS"'s constraints point againt D at @MaikKlein's https://maikklein.github.io/post/cmp-rust-d/
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Demo: duckConstraints.d | |
* Purpose: Demonstrate duck-typed constraints in D (in response to https://maikklein.github.io/2016-03-01-metaprogramming-typeobject/) | |
* Authors: Erich Gubler (Github: @erichdongubler) | |
* Date: 6/25/2016 | |
* | |
* @maikklein: "Constrains" ( ;) ) in D similar to the Rust block you have shown: | |
* | |
* impl<T> Bar<T> | |
* where: T: Copy | |
* { | |
* fn something(&self, val: T) | |
* { | |
* // ... | |
* } | |
* } | |
* | |
* ...can be implemented in several ways, as shown below. You can use `rdmd --build-only --main -unittest duckConstraints.d` to test this. | |
*/ | |
interface Copy | |
{ | |
Copy dup(); | |
} | |
class DupableString : Copy // some implementation of Copy | |
{ | |
string s = ""; | |
override DupableString dup() | |
{ | |
auto newDS = new DupableString; | |
newDS.s = this.s.dup; | |
return newDS; | |
} | |
} | |
// As you mentioned before, we could use dynamic dispatch to resolve calling because we're using an interface: | |
class Foo | |
{ | |
void something(Copy val) | |
{ | |
// ... | |
} | |
} | |
// But the point is that we want static dispatch! We want zero overhead! :) | |
// We can do compile-time constraints with a declaration if, which is Rust's `where` functionality and more: | |
class Bar | |
{ | |
void something(T)(T val) // Interface-based version (equivalent to Rust example above) | |
if(is(T: Copy)) | |
{ | |
pragma(msg, " Using Copy implementation for Bar.something"); | |
} | |
void something_else(T)(T val) // Duck-typed version | |
if(__traits(compiles, val.dup)) | |
{ | |
pragma(msg, " Using duck-typing implementation for Bar.something_else"); | |
} | |
unittest | |
{ | |
pragma(msg, "Doing Bar test"); | |
auto b = new Bar; | |
b.something(new DupableString); | |
b.something_else("asdf"); | |
static assert(!__traits(compiles, b.something("asdf"))); | |
static assert(!__traits(compiles, b.something(42))); // This shouldn't work, because there's no .dup method by default for intstatic assert(__traits(compiles, b.something_else(new DupableString))); | |
} | |
} | |
//...but from what I see, it's more understandable to enforce an interface with static if. | |
class Bar2 | |
{ | |
void something(T)(T val) | |
{ | |
static if(is(T : Copy)) // Static if can be used for multiple conditions if necessary | |
{ | |
pragma(msg, " Using Copy implementation for Bar2.something"); | |
auto stuff = val.dup; | |
} | |
else // You can do even more conditions here -- not just use interfaces in `is` expressions! | |
{ | |
pragma(msg, " Using duck-typing implementation for Bar2.something"); | |
auto stuff = val.dup; // implicitly checked with duck-typing constraints | |
} | |
} | |
unittest | |
{ | |
pragma(msg, "Doing Bar2 test"); | |
auto b2 = new Bar2; | |
b2.something(new DupableString); | |
b2.something("asdf"); | |
static assert(!__traits(compiles, b2.something(42))); // This shouldn't work, because there's no .dup method by default for int | |
} | |
} | |
// But in D, we prefer simple duck typing, which would probably look more like: | |
class Bar3 | |
{ | |
void something(T)(T val) | |
{ | |
auto stuff = val.dup; // implicitly checked with duck-typing constraints | |
} | |
unittest | |
{ | |
pragma(msg, "Doing Bar3 test"); | |
auto b3 = new Bar3; | |
b3.something("asdf"); | |
static assert(!__traits(compiles, b3.something(42))); // This shouldn't work, because there's no .dup method by default for int | |
} | |
} | |
// See how much more concise that is? :) We didn't need an interface or trait at all! | |
// In Rust, we're stuck to using traits to control constraints, but we can use any compile-time conditions in D. | |
// I'd chalk better constraints to D! |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment