July 23, 2015
On 2015-07-23 17:41, Jonathan M Davis wrote:

> Maybe, but the ternary operator is a lot less verbose, and from some
> other comments in this thread, it sounds like the way they implemented
> it in Rust forces you to use braces for single line statements, which
> would be a _huge_ downside IMHO.

Scala implements it without those requirements. I looks exactly like in D, just that it also returns a value.

Also, I think it's getting a lot more interesting when you combine it with automatically return in a method and optional braces for methods with a single expression:

def returnType = if (node.isConstructor)
  None
else
  Some(Type.translate(binding.getReturnType))

Or if you're using pattern matching:

def fromModifier(value: Modifier) = value match {
  case Modifier.ABSTRACT => ABSTRACT
  case Modifier.STATIC => STATIC
  case Modifier.FINAL => FINAL
  case _ => NONE
}

BTW, Ruby supports both the ternary operator and statements are expressions.

-- 
/Jacob Carlborg
July 23, 2015
On 7/23/15 1:51 PM, Timon Gehr wrote:
> On 07/23/2015 06:28 PM, Andrei Alexandrescu wrote:
>> On 7/23/15 10:49 AM, ixid wrote:
>>> On Thursday, 23 July 2015 at 13:33:43 UTC, Adam D. Ruppe wrote:
>>>> On Wednesday, 22 July 2015 at 21:04:57 UTC, simendsjo wrote:
>>>>> :) The example was written to save space. I recon you understand what
>>>>> I mean.
>>>>
>>>> Yeah, but the if/else is one of the most useful examples of it, and is
>>>> covered by ?:, so the whole thing becomes less compelling then.
>>>>
>>>> The other places where I've used it in languages that support it are
>>>> little blocks crammed into a line and sometimes exception grabbing...
>>>> but still, the value isn't that great.
>>>
>>> If we had a clean sheet wouldn't it be better to have if return a value
>>> and ditch ternary?
>>
>> Possibly, but then you'd need to have while return a value. -- Andrei
>
> https://en.wikipedia.org/wiki/Unit_type

I said awkward, not impossible. -- Andrei
July 23, 2015
On 2015-07-23 15:30, Andrei Alexandrescu wrote:

> 1. Inferring function return types when everything is an expression
> (i.e. last expression there is the return type) may yield WAT results.

I have not had that problem with Scala. Either I want to return some thing and let it be inferred, or I don't and declare it as Unit (void).

-- 
/Jacob Carlborg
July 23, 2015
On Thursday, 23 July 2015 at 19:20:20 UTC, Jacob Carlborg wrote:
> On 2015-07-23 15:30, Andrei Alexandrescu wrote:
>
>> 1. Inferring function return types when everything is an expression
>> (i.e. last expression there is the return type) may yield WAT results.
>
> I have not had that problem with Scala. Either I want to return some thing and let it be inferred, or I don't and declare it as Unit (void).

I had a lot of frustration with that (mis)feature and Rust and find it very unreadable. Because of that, so far I always used explicit returns in Rust code even if it is not necessary - that allows to quickly oversee all main exit points of the function.

That is mostly matter of programming culture and hard to resonably justify in any way. Ironically, that would feel more "at home" in D than in Rust because normally latter is much more restrictive and explicit in the code style, such implicit functional syntax sugar feels very alien in typically verbose and detailed code.
July 23, 2015
On 7/23/2015 7:15 AM, Andrei Alexandrescu wrote:
>> I am a bit puzzled by the notion of shipping template code that has
>> never been instantiated as being a positive thing. This has also turned
>> up in the C++ static_if discussions.
>
> This is easy to understand. Weeding out uncovered code during compilation is a
> central feature of C++ concepts. Admitting you actually never want to do that
> would be a major blow.

But if a unit test fails at instantiating it, it fails at compile time.

July 23, 2015
Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
> On 7/23/15 5:07 AM, Walter Bright wrote:
Turns out many constraints in Phobos are of the form (A || B),
>> not just (A && B).
> 
> Agreed. And that's just scratching the surface.
> 
> Serious question: how do you express in Rust that a type implements one trait or another, then figure out statically which?

You define a new trait and implement it differently for A and B.
That leads to a cleaner design IMO because you have to think about the
right abstraction for that trait.

TBH I'm very surprised about that argument, because boolean conditions with version() were dimissed for exactly that reason.

Tobi
July 23, 2015
On Thu, Jul 23, 2015 at 12:49:29PM -0700, Walter Bright via Digitalmars-d wrote:
> On 7/23/2015 7:15 AM, Andrei Alexandrescu wrote:
> >>I am a bit puzzled by the notion of shipping template code that has never been instantiated as being a positive thing. This has also turned up in the C++ static_if discussions.
> >
> >This is easy to understand. Weeding out uncovered code during compilation is a central feature of C++ concepts. Admitting you actually never want to do that would be a major blow.
> 
> But if a unit test fails at instantiating it, it fails at compile time.

That assumes the template author is diligent (foolhardy?) enough to write unittests that cover all possible instantiations...


T

-- 
People say I'm indecisive, but I'm not sure about that. -- YHL, CONLANG
July 23, 2015
On 7/23/2015 8:03 AM, Dicebot wrote:
> At the same time one HUGE deal breaker with rust traits that rarely gets
> mentioned is the fact that they are both constraints and interfaces at the same
> time:
>
> // this is template constraint, it will generate new `foo` symbol for each new T
> fn foo <T : InputRange> (range : T)
>
> // this use the very same trait definition but creates "fat pointer" on demand
> with simplistic dispatch table
> fn foo (range : InputRange)
>
> It kills all the necessity for hacks like RangeObject and is quite a salvation
> once you get to defining dynamic shared libraries with stable ABI.
>
> This is probably my most loved feature of Rust.

D interface types also produce the simplistic dispatch table, and if you make them extern(C++) they don't need a RangeObject. I know it isn't as convenient as what you describe above, but it can be pressed into service.

July 23, 2015
"jmh530" <john.michael.hall@gmail.com> wrote:
> I feel like it's hard to separate borrowing from Rust's variety of
> pointers (& is borrowed pointer, ~ is for unique pointer, @ is for managed pointer).

That's actually very outdated information. Two of the four pointer types (&,@,~ and *) were ditched in favor of library solutions.

*T: Raw pointers are still the same
&T: is now called reference, not borrowed pointer
~T: Is now Box<T>
@T: Is now Rc<T> (and possibly Gc<T> although a GC was never implemented)
 Tobi
July 23, 2015
On Thursday, 23 July 2015 at 19:55:30 UTC, Walter Bright wrote:
> On 7/23/2015 8:03 AM, Dicebot wrote:
>> At the same time one HUGE deal breaker with rust traits that rarely gets
>> mentioned is the fact that they are both constraints and interfaces at the same
>> time:
>>
>> // this is template constraint, it will generate new `foo` symbol for each new T
>> fn foo <T : InputRange> (range : T)
>>
>> // this use the very same trait definition but creates "fat pointer" on demand
>> with simplistic dispatch table
>> fn foo (range : InputRange)
>>
>> It kills all the necessity for hacks like RangeObject and is quite a salvation
>> once you get to defining dynamic shared libraries with stable ABI.
>>
>> This is probably my most loved feature of Rust.
>
> D interface types also produce the simplistic dispatch table, and if you make them extern(C++) they don't need a RangeObject. I know it isn't as convenient as what you describe above, but it can be pressed into service.

I am not sure how it applies. My point was about the fact that `isInputRange` and `InputRangeObject` are the same entities in Rust, simply interpreted differently by compiler depending on usage context.

This is important because you normally want to design your application in terms of template constraints and structs to get most out of inlining and optimization. However, to define stable ABI for shared libraries, the very same interfaces need to be wrapped in runtime polymorphism.

Closest thing in D would be to define traits as interfaces and use code like this:

void foo(T)()
    if (  (is(T == struct) || is(T == class))
       && Matches!(T, Interface)
    )
{ }

where `Matches` is a template helper that statically iterates method list of interface and looks for matching methods in T. However, making it built-in feels really convenient in Rust:

- considerably less function declaration visual noise
- much better error messages: trying to use methods of T not defined by a trait will result in compile-time error even without instantiating the template