October 29, 2017
On Sunday, 29 October 2017 at 20:15:41 UTC, Ola Fosheim Grøstad wrote:
> On Sunday, 29 October 2017 at 20:05:08 UTC, Steven Schveighoffer wrote:
>> It's actually perfect for generic code. If you need something other than the current "0 means false" behavior (like for instance int), then you wrap in a type that opCast!bool means what you want.
>
> I think we just have to agree that we disagree. Generic programming relies on consistent protocols.
>
> So, you generally don't want 0 to be considered as an invalid value. Because of the defaults in D, cast(bool) isn't really all that useful.
>
> It would have been better if the default was to deny casting to bool, but that is too late as D has decided to be too close to C on so many levels, so it would be a bad idea to diverge from C for that now. So the next best thing is to let the programmer specify that something is invalid with some other means than opCast to bool.
>
> *shrug*

But casting to bool is what you use to tell whether something is valid or not.

true = valid, false = invalid.

If you want 0 to be valid for a type then you wrap around it with opCast.

Ex.

---
import std.stdio;

struct MyInt
{
	int value;
	
	bool opCast(T : bool)()
	{
		return value >= 0;
	}
}

void main()
{
	MyInt a = MyInt(1);
	MyInt b = MyInt(0);
	MyInt c = MyInt(-1);
	
	if (a) writeln("a is valid");
	if (b) writeln("b is valid");
	if (c) writeln("c is valid");
}
---

Output:
a is valid
b is valid
October 29, 2017
On Sunday, 29 October 2017 at 20:37:21 UTC, bauss wrote:
> But casting to bool is what you use to tell whether something is valid or not.
>
> true = valid, false = invalid.


Not really. In mathematics 0 and 1 can be considered as "true" and "false" for a 2-value calculus, while you might reserve ⊤ and ⊥ for true and false in the logic you use to reason about that calculus.

Which is why some languages assumes an equality between 0 and true and 1 and false, but that does not by necessity suggest valid/invalid.

On the other hand. For things like Unix function call return values -1 is often used to signify an invalid result, and 0 does not signify failure.

So if you want strict typing, you have to do something else. Because C  (and thus D) takes the mathematical view on the relationship between integers and bools and propagate that view to all other basic types (e.g. floats).


Ola.
October 30, 2017
One man's valid value is another man's invalid value. You can't test for a general concept of "invalid," as you need context. You can test for "falsy" with no context.
October 30, 2017
On Monday, 30 October 2017 at 00:10:13 UTC, w0rp wrote:
> One man's valid value is another man's invalid value. You can't test for a general concept of "invalid," as you need context. You can test for "falsy" with no context.

No, associating the numeral "0" with "false" is forcing a particular interpretation of int as representing a count of something. That is not an inate quality of the integer programming language type as such. For instance, there is no reason for "0 fahrenheit" to be "false". Only if "0" represents the "empty set" would that interpretation make some sense.

Yes, you can obviously have a general concept of invalid in a strict typing system.

October 30, 2017
On Sunday, 29 October 2017 at 20:37:21 UTC, bauss wrote:
> On Sunday, 29 October 2017 at 20:15:41 UTC, Ola Fosheim Grøstad wrote:
>> [...]
>
> But casting to bool is what you use to tell whether something is valid or not.
>
> true = valid, false = invalid.
>
> If you want 0 to be valid for a type then you wrap around it with opCast.
>
> Ex.
>
> ---
> import std.stdio;
>
> struct MyInt
> {
> 	int value;
> 	
> 	bool opCast(T : bool)()
> 	{
> 		return value >= 0;
> 	}
> }
>
> void main()
> {
> 	MyInt a = MyInt(1);
> 	MyInt b = MyInt(0);
> 	MyInt c = MyInt(-1);
> 	
> 	if (a) writeln("a is valid");
> 	if (b) writeln("b is valid");
> 	if (c) writeln("c is valid");
> }
> ---
>
> Output:
> a is valid
> b is valid

TL;DR

This could be done by maybe monad.

int? a = 0;
if (a) writeln("a is valid");



BTW: Thanks for implementing the Elvis feature.
October 30, 2017
On Saturday, 28 October 2017 at 11:38:52 UTC, Andrei Alexandrescu wrote:
> Walter and I decided to kick-off project Elvis for adding the homonym operator to D.
>
> Razvan Nitu has already done a good part of the work:
>
> https://github.com/dlang/dmd/pull/7242
> https://github.com/dlang/dlang.org/pull/1917
> https://github.com/dlang/dlang.org/pull/1918

Is it going to be something similar (or the same) as in Kotlin? (Reference: https://kotlinlang.org/docs/reference/null-safety.html#elvis-operator )

I see from comments that different people think of it in a different way. I suggest them to read this section from Kotlin docs to understand the reasoning behind the elvis operator.
October 30, 2017
On 10/30/17 7:32 AM, Dejan Lekic wrote:
> On Saturday, 28 October 2017 at 11:38:52 UTC, Andrei Alexandrescu wrote:
>> Walter and I decided to kick-off project Elvis for adding the homonym operator to D.
>>
>> Razvan Nitu has already done a good part of the work:
>>
>> https://github.com/dlang/dmd/pull/7242
>> https://github.com/dlang/dlang.org/pull/1917
>> https://github.com/dlang/dlang.org/pull/1918
> 
> Is it going to be something similar (or the same) as in Kotlin? (Reference: https://kotlinlang.org/docs/reference/null-safety.html#elvis-operator )
> 
> I see from comments that different people think of it in a different way. I suggest them to read this section from Kotlin docs to understand the reasoning behind the elvis operator.

From looking quickly at that, but not having any experience with Kotlin (but having some experience with Swift), I think this really requires a concept of Nullable types being a builtin feature. The idea is to have something that always results in a non-null value.

Swift uses the operator ?? to do the same thing (search for ?? on this page: https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/BasicOperators.html)

I think D has the capability of doing the same thing, even with Nullable being a library type, but would have to be pervasive in usage to look like Kotlin. At least the operator itself fits into the usage of Null or not types. Of course, the D version is much more adaptable, as any concept of "Null" or "Invalid" can be ascribed to a type via the opCast(bool) function.

-Steve
October 30, 2017
On 10/29/17 3:10 PM, Nemanja Boric wrote:
> We've already reported this as a bug (I actually got quite burned on it, trusting assert(float_value) to prevent NaN's escaping the function), but there were different opinions on this, so it never got anywhere: https://issues.dlang.org/show_bug.cgi?id=13489

Wow, interesting dialog there.

I'm in the camp that nan should be evaluated as false. I don't think I like the idea that !nan is also false, because this makes !!nan true!

TBH, I don't think I ever considered doing if(floatingpointvalue) to be a good idea in C or D. I generally stay away from float, and especially comparing to 0 directly.

-Steve
October 30, 2017
On 10/30/17 7:32 AM, Dejan Lekic wrote:
> On Saturday, 28 October 2017 at 11:38:52 UTC, Andrei Alexandrescu wrote:
>> Walter and I decided to kick-off project Elvis for adding the homonym operator to D.
>>
>> Razvan Nitu has already done a good part of the work:
>>
>> https://github.com/dlang/dmd/pull/7242
>> https://github.com/dlang/dlang.org/pull/1917
>> https://github.com/dlang/dlang.org/pull/1918
> 
> Is it going to be something similar (or the same) as in Kotlin? (Reference: https://kotlinlang.org/docs/reference/null-safety.html#elvis-operator )
> 
> I see from comments that different people think of it in a different way. I suggest them to read this section from Kotlin docs to understand the reasoning behind the elvis operator.

The principle of least astonishment indicates we should do what the lowering does:


expr1 ?: expr2

==>

(x => x ? x : expr2)(expr1)

An approach that does things any differently would have a much more difficult time. It is understood (and expected) that other languages have subtly different takes on the operator.


Andrei

October 30, 2017
On Monday, October 30, 2017 11:04:32 Steven Schveighoffer via Digitalmars-d wrote:
> On 10/29/17 3:10 PM, Nemanja Boric wrote:
> > We've already reported this as a bug (I actually got quite burned on it, trusting assert(float_value) to prevent NaN's escaping the function), but there were different opinions on this, so it never got anywhere: https://issues.dlang.org/show_bug.cgi?id=13489
>
> Wow, interesting dialog there.
>
> I'm in the camp that nan should be evaluated as false. I don't think I like the idea that !nan is also false, because this makes !!nan true!
>
> TBH, I don't think I ever considered doing if(floatingpointvalue) to be a good idea in C or D. I generally stay away from float, and especially comparing to 0 directly.

Yeah. Honestly, I stay away from if(x) in general if x isn't a bool. I might
occasionally do it for a pointer, but it's not like floating point types are
the only ones that act badly with cast(bool) (e.g. dynamic arrays). It all
works just fine if you understand what each of the types do with cast(bool),
but it's just clearer if you make the check it explicit.

I avoid floating point types on general principle though - not just in if statements. I'll use them when I need them, but if I can reasonably do something with an integral type instead, I will, because I don't want to deal with the inaccuracies of FP math. The fact that NaN == NaN is false and yet cast(bool)NaN is true though is just attrocious though. We aren't source compatible with C like C++ is, and yet we're still bound by it in so many small, stupid ways - largely because of the risk of ported code going badly.

- Jonathan M Davis