July 26, 2015
On 07/25/2015 02:19 PM, Andrei Alexandrescu wrote:
> On 7/23/15 5:26 PM, Ziad Hatahet via Digitalmars-d wrote:
>> On Thu, Jul 23, 2015 at 2:00 PM, Adam D. Ruppe via Digitalmars-d
>> <digitalmars-d@puremagic.com <mailto:digitalmars-d@puremagic.com>> wrote:
>>
>>     I think it is actually kinda pretty:
>>
>>
>> What about:
>>
>> int median(int a, int b, int c) {
>>      return (a<b) ? (b<c) ? b : (a<c) ? c : a : (a<c) ? a : (b<c) ? c
>> : b;
>> }
>>
>> vs.
>>
>> def median(a: Int, b: Int, c: Int) =
>>    if (a < b) {
>>      if (b < c) b
>>      else if (a < c) c
>>      else a
>>    }
>>    else if (a < c) a
>>    else if (b < c) c
>>    else b
>
> This is a wash. If we want to discuss good things in Rust

(The quoted bit is Scala code.)

> we could get inspiration from, we need relevant examples. -- Andrei
>

What do you mean?

I think it is pretty obvious that 'if'/'else' is "better" syntax than '?:'. It e.g. does not leave the separation of context and condition up to operator precedence rules and is hence easier to parse by a human. Not that I'd care much, but it is inconvenient to be asked not to use the ternary operator in team projects just because it has a badly engineered syntax.

Also, we have (int x){ return r; }, auto foo(int x){ return r; }, (int x)=>r, but not auto foo(int x)=>r. It's an arbitrary restriction.


(BTW: To all the people who like to put the ternary operator condition into parens in order to imitate if: A convention that makes more sense here is to put the entire (chained) ternary expression in parentheses.)
July 26, 2015
On 7/25/15 6:48 PM, deadalnix wrote:
> On Saturday, 25 July 2015 at 09:40:52 UTC, Walter Bright wrote:
>> On 7/25/2015 12:19 AM, Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?=
>> <ola.fosheim.grostad+dlang@gmail.com> wrote:
>>> The point of having a type system is to catch as many mistakes at
>>> compile time
>>> as possible. The primary purpose of a type system is to reduce
>>> flexibility.
>>
>> Again, the D constraint system *is* a compile time system, and if the
>> template body uses an interface not present in the type and not
>> checked for in the constraint, you will *still* get a compile time error.
>>
>> The idea that Rust traits check at compile time and D does not is a
>> total misunderstanding.
>>
>
> Obvious, everything is at compile time here. Still, there is 2 steps,
> compiling the template (equivalent to compile time in the dynamic
> dispatch case), and instantiating the template (equivalent to runtime in
> the dynamic dispatch case).
>
> That is the exact same problem.

Probably that's the root of all disagreement. So we have template writing time, template instantiation time, and just run time. I think template instantiation time is a lot "closer" to template writing time than run time. -- Andrei

July 26, 2015
On 7/25/15 6:54 PM, deadalnix wrote:
> On Saturday, 25 July 2015 at 10:05:35 UTC, Tofu Ninja wrote:
>> On Saturday, 25 July 2015 at 09:40:52 UTC, Walter Bright wrote:
>>> if the template body uses an interface not present in the type and
>>> not checked for in the constraint, you will *still* get a compile
>>> time error.
>>
>> But only if the template gets instantiated with a bad type. Unit tests
>> don't catch every thing and have to be written properly. A proper type
>> system should catch it.
>
> This unitest argument is becoming ridiculous. Unless some strong
> argument is brought to the table that this differs from the "dynamic
> typing is not a problem if you write unitest" we we all should know is
> bogus at this point, it can't be taken seriously.

To me that's self understood. Run time is fundamentally different from everything preceding it. -- Andrei
July 26, 2015
On 07/25/2015 02:18 PM, Andrei Alexandrescu wrote:
> On 7/23/15 4:47 PM, Ziad Hatahet via Digitalmars-d wrote:
>> On the other hand, Rust does not require parenthesis around if
>> conditions:
>
> Yet it requires braces around the arms. Rust taketh away, Rust requireth
> back :o). -- Andrei

It's arguably a better trade-off.
July 26, 2015
On 7/25/15 7:10 PM, deadalnix wrote:
> On Saturday, 25 July 2015 at 13:37:15 UTC, Andrei Alexandrescu wrote:
>> On 7/24/15 6:12 PM, deadalnix wrote:
>>> The most intriguing part of this conversation is that the argument made
>>> about unitests and complexity are the very same than for dynamic vs
>>> strong typing (and there is hard data that strong typing is better).
>>
>> No, that's not the case at all. There is a distinction: in dynamic
>> typing the error is deferred to run time, in this discussion the error
>> is only deferred to instantiation time. -- Andrei
>
> In case 1, it is argued that unitest check runtime, so we are good, and
> in case 2, unitest check instantiation, so we are good.
>
> That is the very same argument and it is equally bogus in both cases.

I don't see it as the same argument. I do agree that applied to runtime it is specious. -- Andrei
July 26, 2015
On 7/25/15 7:14 PM, deadalnix wrote:
> On Saturday, 25 July 2015 at 13:59:11 UTC, Andrei Alexandrescu wrote:
>> Understood, but by the same token library authors shouldn't ship
>> untested code. This is basic software engineering. Once we agree on
>> that, we figure that concepts help nobody. -- Andrei
>
> Understood, but by the same token library authors shouldn't ship
> untested code. This is basic software engineering. Once we agree on
> that, we figure that [type system|grizzly|unicorns] help nobody.
>
> That is a statement, not an argument.

Well then don't clip the context. -- Andrei

July 26, 2015
On 07/25/2015 02:15 PM, Andrei Alexandrescu wrote:
> On 7/23/15 4:52 PM, Walter Bright wrote:
>> On 7/23/2015 1:08 PM, Dicebot wrote:
>>  > I am not sure how it applies.
>>
>> D interfaces (defined with the 'interface' keyword) are simple dispatch
>> types, they don't require an Object. Such interfaces can also have
>> default implementations.
>
> Is this new? I agree we should allow it, but I don't think it was added
> to the language yet.
>
> Andrei

In any case, the painful thing about the RangeObject interfaces is that they transform value types into reference types.
July 26, 2015
On 7/26/15 5:04 AM, deadalnix wrote:
> On Sunday, 26 July 2015 at 00:18:14 UTC, Walter Bright wrote:
>> On 7/25/2015 3:59 PM, deadalnix wrote:
>>> On Saturday, 25 July 2015 at 12:05:12 UTC, Andrei Alexandrescu wrote:
>>>> Well at least all paths must be compiled. You wouldn't ship
>>>> templates that
>>>> were never instantiated just as much as you wouldn't ship any code
>>>> without
>>>> compiling it. We've had a few cases in Phobos a while ago of
>>>> templates that
>>>> were never instantiated, with simple compilation errors when people
>>>> tried to
>>>> use them. -- Andrei
>>>
>>> That is an instance of happy case testing. You test that what you
>>> expect to work
>>> work. You can't test that everything that is not supposed to work do
>>> not, or
>>> that you don't rely on a specific behavior of the thing you are testing.
>>>
>>
>> Um, testing all paths is not happy case testing.
>
> You test all execution path, not all "instantiation path". Consider
> this, in a dynamically typed language, you can have a function that
> accept a string and do something with it. You can write unit tests to
> check it does the right thing with various strings and make sure it
> execute all path.
>
> Yet, what happen when it is passed an int ? a float ? an array ? an
> object ? Probably random shit.
>
> Same here, but at instantiation time.

No, you are very wrong here. I am sorry! Instantiation testing is making sure that syntactic conformance is there. Semantic conformance cannot be tested during compilation (big difference) and can be partially verified dynamically.

This whole conflation with dynamic typing/unittesting is inappropriate and smacks of https://en.wikipedia.org/wiki/Argument_from_analogy. If you have a point, make it stand on its own.


Andrei

July 26, 2015
On 7/26/15 11:18 AM, Timon Gehr wrote:
> I think it is pretty obvious that 'if'/'else' is "better" syntax than '?:'.

It may as well be the case but the whole deal is marginal. Yeah, we could have slightly better tactical tools for expressing conditionals, but really we're fine. -- Andrei

July 26, 2015
On Sunday, 26 July 2015 at 06:54:17 UTC, Jonathan M Davis wrote:
>
> That's certainly an interesting idea, though if we're going that route, it might be better to simply have the compiler do that automatically for you, since it can see what functions are being called and what they're constraints are. Still, part of the problem is that the constraints for bar or baz may not be directly related to the argument to foo but rather to a result of operating on it. So, bar and baz's constraints can't necessarily be moved up into foo's constraint like that in a meaningful way. It would require the code that generates the arguments to bar and baz as well in order to make that clear. For instance, it might be that T needs to be an input range for the code that's directly in foo. However, if you do something like
>
> auto u = t.f1().f2().f3();
> auto b = bar(u);
>

Yeah, I can see how something like that's going to get complicated. My best guess would be something like
auto foo(T)(T t)
{
    static if ( template_constraints!f1(t) && template_constraints!f2(f1(t)) && template_constraints!f3(f2(f1(t))) )
        auto u = t.f1().f2().f3();
        static if (template_constraints!bar(u))
            auto b = bar(u);
}

I guess the key would be that the template_constraints should be able to take whatever inputs the function can take so that you can use it with static if at any point in the function body if needed. It may not work for everything, but I imagine it would probably cover most cases, albeit awkwardly for the chained range operations. Ideally, there could be a way so that only the last condition in that first static if is required, but I'm not sure how easy something like that would be.

Nevertheless, I honestly don't know how big of an issue something like this is. I'm sort of talking out of ignorance at this point. I haven't had the need to program anything like this.

My biggest problem with your point about including everything in the top-level is that if you make a change to the constraints in the bottom level then you have to remember to make the changes everywhere else. If you only allow one template constraint for each function, then it might be easier to remember (b/c multiple conditions would need to be defined in auxiliary functions), but it would also be much less flexible.