Thread overview | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
April 30, 2014 D vs Rust: function signatures | ||||
---|---|---|---|---|
| ||||
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 |
April 30, 2014 Re: D vs Rust: function signatures | ||||
---|---|---|---|---|
| ||||
Posted in reply to Narrator | 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.
|
April 30, 2014 Re: D vs Rust: function signatures | ||||
---|---|---|---|---|
| ||||
Posted in reply to Narrator | 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. |
April 30, 2014 Re: D vs Rust: function signatures | ||||
---|---|---|---|---|
| ||||
Posted in reply to Nick Sabalausky | 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. :)
|
April 30, 2014 Re: D vs Rust: function signatures | ||||
---|---|---|---|---|
| ||||
Posted in reply to Narrator | 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.
|
April 30, 2014 Re: D vs Rust: function signatures | ||||
---|---|---|---|---|
| ||||
Posted in reply to Nick Sabalausky | 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
|
April 30, 2014 Re: D vs Rust: function signatures | ||||
---|---|---|---|---|
| ||||
Posted in reply to Paulo Pinto | 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. ;)
|
April 30, 2014 Re: D vs Rust: function signatures | ||||
---|---|---|---|---|
| ||||
Posted in reply to Vladimir Panteleev | 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.
|
Copyright © 1999-2021 by the D Language Foundation