www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - D vs Rust: function signatures

reply "Narrator" <narrator gmail.com> writes:
The unbelievable amount of time and energy that's been spent 
discussing the smallest syntax, you would think that D would, at 
the very least, have better looking function signatures, but it 
doesn't.

auto zip(Ranges...)(Ranges ranges) if (Ranges.length && 
allSatisfy!(isInputRange, Ranges));
auto zip(Ranges...)(StoppingPolicy sp, Ranges ranges) if 
(Ranges.length && allSatisfy!(isInputRange, Ranges));

fn zip<B, U: Iterator<B>>(self, other: U) -> Zip<Self, U>


auto chain(Ranges...)(Ranges rs) if (Ranges.length > 0 && 
allSatisfy!(isInputRange, staticMap!(Unqual, Ranges)) && 
!is(CommonType!(staticMap!(ElementType, staticMap!(Unqual, 
Ranges))) == void));

fn chain<U: Iterator<A>>(self, other: U) -> Chain<Self, U>


template map(fun...) if (fun.length >= 1)
auto map(Range)(Range r) if (isInputRange!(Unqual!Range));

fn map<'r, B>(self, f: |A|: 'r -> B) -> Map<'r, A, B, Self>


template filter(alias pred) if (is(typeof(unaryFun!pred)))
auto filter(Range)(Range rs) if (isInputRange!(Unqual!Range));

fn filter<'r>(self, predicate: |&A|: 'r -> bool) -> Filter<'r, A, 
Self>


MaxType!(T1, T2, T) max(T1, T2, T...)(T1 a, T2 b, T xs) if 
(is(typeof(a < b)));

pub fn max<T: TotalOrd>(v1: T, v2: T) -> T
Apr 29 2014
next sibling parent reply Nick Sabalausky <SeeWebsiteToContactMe semitwist.com> writes:
On 4/29/2014 9:38 PM, Narrator wrote:
 fn map<'r, B>(self, f: |A|: 'r -> B) -> Map<'r, A, B, Self>

That looks like line noise.
Apr 29 2014
parent Nick Sabalausky <SeeWebsiteToContactMe semitwist.com> writes:
On 4/30/2014 3:26 AM, Paulo Pinto wrote:
 On Wednesday, 30 April 2014 at 01:49:01 UTC, Nick Sabalausky wrote:
 On 4/29/2014 9:38 PM, Narrator wrote:
 fn map<'r, B>(self, f: |A|: 'r -> B) -> Map<'r, A, B, Self>

That looks like line noise.

Not if one is used to ML languages. Beauty is in the eyes of the beholder. :)

FWIW, I do agree (Not that I know much about ML-family). The "...to me" was carelessly left as implied. ;)
Apr 30 2014
prev sibling next sibling parent reply "Vladimir Panteleev" <vladimir thecybershadow.net> writes:
On Wednesday, 30 April 2014 at 01:38:46 UTC, Narrator wrote:
 The unbelievable amount of time and energy that's been spent 
 discussing the smallest syntax, you would think that D would, 
 at the very least, have better looking function signatures, but 
 it doesn't.

 auto zip(Ranges...)(Ranges ranges) if (Ranges.length && 
 allSatisfy!(isInputRange, Ranges));
 auto zip(Ranges...)(StoppingPolicy sp, Ranges ranges) if 
 (Ranges.length && allSatisfy!(isInputRange, Ranges));

 fn zip<B, U: Iterator<B>>(self, other: U) -> Zip<Self, U>

IIUC: 1. The Rust function is non-variadic 2. The Rust function has no StoppingPolicy equivalent 3. The Rust function is a method of some type, such as Zip or Chain, which must be declared explicitly in every such type. Here is the equivalent D syntax: auto zip(R)(R other) if (isInputRange!R) It is shorter than the Rust version.
 auto chain(Ranges...)(Ranges rs) if (Ranges.length > 0 && 
 allSatisfy!(isInputRange, staticMap!(Unqual, Ranges)) && 
 !is(CommonType!(staticMap!(ElementType, staticMap!(Unqual, 
 Ranges))) == void));

 fn chain<U: Iterator<A>>(self, other: U) -> Chain<Self, U>

Same as points 1 and 3 above. Most of that boilerplate comes from validating the variadic parameter types.
 template map(fun...) if (fun.length >= 1)
 auto map(Range)(Range r) if (isInputRange!(Unqual!Range));

 fn map<'r, B>(self, f: |A|: 'r -> B) -> Map<'r, A, B, Self>

Same as points 1 and 3 above (D's version allows specifying multiple functions). Not sure what 'r or |A| means in Rust syntax, but I guess this would be the equivalent D syntax: auto map(R)(R delegate(T)) Note that D's real version has the function alias as a template parameter, and not as a runtime parameter, meaning that you will have a guarantee of a separate template instantiation for every different map predicate. This allows you to make assumptions about the performance of the generated code which don't rely as much on expected compiler optimizations (although I don't know what guarantees Rust makes about this).
 template filter(alias pred) if (is(typeof(unaryFun!pred)))
 auto filter(Range)(Range rs) if (isInputRange!(Unqual!Range));

 fn filter<'r>(self, predicate: |&A|: 'r -> bool) -> Filter<'r, 
 A, Self>

As above, though D's filter also accepts only one predicate.
 MaxType!(T1, T2, T) max(T1, T2, T...)(T1 a, T2 b, T xs) if 
 (is(typeof(a < b)));

 pub fn max<T: TotalOrd>(v1: T, v2: T) -> T

Same as point 1 above. Also, the Rust version requires that the two values have exactly the same type.
Apr 29 2014
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 04/30/2014 04:04 AM, Vladimir Panteleev wrote:
 fn map<'r, B>(self, f: |A|: 'r -> B) -> Map<'r, A, B, Self>

Same as points 1 and 3 above (D's version allows specifying multiple functions). Not sure what 'r or |A| means in Rust syntax, but I guess this would be the equivalent D syntax: auto map(R)(R delegate(T))

|A| -> B is the type of a closure mapping an A to a B. 'r is a lifetime parameter (there is another one in Self): I.e. that signature is roughly saying: The returned iterator lives at most as long as the closure context of f and the underlying iterator. This way you can eg. get an iterator over some mutable data structure, map it without allocations using a stack closure, and the type system verifies that the data structure is not changed while the mapped iterator is in use, and that there are no dangling references to stack memory left behind.
Apr 30 2014
prev sibling next sibling parent "Paulo Pinto" <pjmlp progtools.org> writes:
On Wednesday, 30 April 2014 at 01:49:01 UTC, Nick Sabalausky 
wrote:
 On 4/29/2014 9:38 PM, Narrator wrote:
 fn map<'r, B>(self, f: |A|: 'r -> B) -> Map<'r, A, B, Self>

That looks like line noise.

Not if one is used to ML languages. Beauty is in the eyes of the beholder. :)
Apr 30 2014
prev sibling next sibling parent "John Colvin" <john.loughran.colvin gmail.com> writes:
On Wednesday, 30 April 2014 at 01:38:46 UTC, Narrator wrote:
 The unbelievable amount of time and energy that's been spent 
 discussing the smallest syntax, you would think that D would, 
 at the very least, have better looking function signatures, but 
 it doesn't.

 auto zip(Ranges...)(Ranges ranges) if (Ranges.length && 
 allSatisfy!(isInputRange, Ranges));
 auto zip(Ranges...)(StoppingPolicy sp, Ranges ranges) if 
 (Ranges.length && allSatisfy!(isInputRange, Ranges));

 fn zip<B, U: Iterator<B>>(self, other: U) -> Zip<Self, U>


 auto chain(Ranges...)(Ranges rs) if (Ranges.length > 0 && 
 allSatisfy!(isInputRange, staticMap!(Unqual, Ranges)) && 
 !is(CommonType!(staticMap!(ElementType, staticMap!(Unqual, 
 Ranges))) == void));

 fn chain<U: Iterator<A>>(self, other: U) -> Chain<Self, U>


 template map(fun...) if (fun.length >= 1)
 auto map(Range)(Range r) if (isInputRange!(Unqual!Range));

 fn map<'r, B>(self, f: |A|: 'r -> B) -> Map<'r, A, B, Self>


 template filter(alias pred) if (is(typeof(unaryFun!pred)))
 auto filter(Range)(Range rs) if (isInputRange!(Unqual!Range));

 fn filter<'r>(self, predicate: |&A|: 'r -> bool) -> Filter<'r, 
 A, Self>


 MaxType!(T1, T2, T) max(T1, T2, T...)(T1 a, T2 b, T xs) if 
 (is(typeof(a < b)));

 pub fn max<T: TotalOrd>(v1: T, v2: T) -> T

I don't think a single one of those signatures are equivalent. Also, bear in mind that those if() constraints contain arbitrary code (as long as it can be evaluated at compile-time), so they are very flexible.
Apr 30 2014
prev sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Nick Sabalausky:
 On 4/29/2014 9:38 PM, Narrator wrote:
 fn map<'r, B>(self, f: |A|: 'r -> B) -> Map<'r, A, B, Self>

That looks like line noise.

In D there is a lambda syntax: auto F = (in int x) => x ^^ 2; void main() { int y; auto G = (in int x) => x + y; pragma(msg, typeof(F)); pragma(msg, typeof(G)); } That code contains the types (the pragma output is a little different): int function(in int) pure nothrow nogc safe int delegate(in int) nothrow nogc safe An alternative syntax can be similar to the way you write D lamdas: (in int) pure nothrow nogc safe => int (in int) nothrow nogc safe ==> int (I am not suggesting to introduce this syntax to D because its an useless duplication, but I find it a bit better.) Bye, bearophile
Apr 30 2014