View mode: basic / threaded / horizontal-split · Log in · Help
December 24, 2011
Re: BigInt bool assign
On Sat, 24 Dec 2011 21:33:33 +1100, Don <nospam@nospam.com> wrote:

> I think stuff like
> int z +=  x > y;
> should ideally require a cast. That's a crazy operation.

I would go so fas as saying that such an idiom ought to be coded as ...

  if (x > y) {
     z++;
  }

or if insists on a one-liner ...

  z += (x > y ? 1 : 0);

-- 
Derek Parnell
Melbourne, Australia
December 24, 2011
Re: BigInt bool assign
On 12/24/2011 04:33 AM, Don wrote:
> On 24.12.2011 02:30, Derek wrote:
>> On Sat, 24 Dec 2011 09:19:26 +1100, bearophile
>> <bearophileHUGS@lycos.com> wrote:
>>
>>> This is why it's better to avoid casts, not requiring them in the
>>> first place, unless they are useful. In this case I think a cast
>>> introduces more danger than the risks caused by implicit bool->int
>>> conversions.
>>
>> If we assume that explicit casts are required for bool->int conversion,
>> can you show some code in which this could cause a problem?
>
> I think stuff like
> int z += x > y;
> should ideally require a cast. That's a crazy operation.

Love that one...

Andrei
December 24, 2011
Re: BigInt bool assign
On Sun, 25 Dec 2011 00:09:08 +1100, bearophile <bearophileHUGS@lycos.com>  
wrote:

> Derek Parnell:
>
>>> In my code such mistakes are uncommon.
>
>> But not impossible.
>
> Designing an engineering system like a programming language is often a  
> matter of trade-offs. If in my code I find a problem (like integer  
> overflows) quite more common than other ones (like bugs caused by  
> implicit bool->int conversions) it is very right for me to desire the  
> first ones issued first. Priorities are really important in engineering.

I agree that priorities are extremely important. However, I'm not seeing  
that this bool->int conversion is an either-or situation. We are not being  
forced to choose between integer overflow issues and bool->int conversion  
issues. Our code should, right now, cater for both issues as it is not  
really a great deal of work to write code that deals with both.

> I believe that casts often "shut up the compiler" but I don't belive  
> that's their purpose. One of their main purposes is to offer a standard  
> way to break the static type system in specific points of the program.  
> Every type system restricts the number of the acceptable programs. But  
> programmers sometimes want to write some of those programs. To do this  
> they sometimes use casts. D casts have other secondary purposes, like  
> bit reinterpretation, etc.

Yes, 'cast' is a poor choice of word here. Sometimes we need to tell the  
compiler to do a data conversion (transforming bits into a new format) and  
sometimes we need to tell it to assume that the bits are already in the  
correct format even though it would not otherwise agree with you.

One issue you have highlighted below is that 'cast(T)' is not exactly  
totally explicit. The coder cannot simply tell if it is doing a data  
conversion or a data re-interpretation. That requires some background  
knowledge about D's internals. Furthermore, when doing a data conversion,  
the 'cast(T)' syntax is only explicit about the target format; it implies  
the source format from the datatype of its operand. And as you point out  
below, that can be a source of bugs.

>>> In practice my experience shows that the programmer (me too) sometimes
>>> doesn't have perfect knowledge (usually because the code later was
>>> modified, turning the cast into a bug because casts are often silent).
>
>> You realize that the exact argument can be made about implicit casts.
>
> You are missing something important. Currently this code compiles, it  
> performs a silent implicit cast:
>
> bool foo() { return true; }
> void main() {
>     int x = foo();
> }
>
>
> Now you change the code, foo returns a double, the implicit cast stops  
> being accepted and the compiler gives an error:
>
> double foo() { return 1.5; }
> void main() {
>     int x = foo();
> }
>
>
> The same doesn't happen if you use an explicit cast. This is the  
> original code if we now require a cast to assign a bool to an int:
>
> bool foo() { return true; }
> void main() {
>     int x = cast(int)foo();
> }
>
>
> Now if you modify the code, so foo returns a double, the cast keeps  
> silencing the compiler and this is a possible bug that goes unnoticed  
> (you lose information doing double->int, while bit->int doesn't lose  
> information):
>
>
> double foo() { return 1.5; }
> void main() {
>     int x = cast(int)foo();
> }


Yes, I agree that this is a potential source of bugs. So what we need is  
something more explicit.

 double foo() { return 1.5; }
 void main() {
     int x = cast(double:int)foo();
 }

Now the code is very clear about your intentions for it, and if foo() is  
later modified to return some incompatible datatype, the compile can alert  
the coder.

And to be consistent, we need to have syntax that allows a coder to  
explicitly tell the compiler to do a re-interpretation cast.

-- 
Derek Parnell
Melbourne, Australia
December 24, 2011
Re: BigInt bool assign
My post seems to have been lost because of NG malfunction.

On 12/24/2011 09:17 AM, Don wrote:
>> On 24.12.2011 01:32, Timon Gehr wrote:
>>> On 12/23/2011 11:34 PM, Jonathan M Davis wrote:
>>>> On Friday, December 23, 2011 17:19:26 bearophile wrote:
>>>>> Derek Parnell:
>>>>>> I'm with Don on this one because a boolean and an integer are not the
>>>>>> same concept, and even though many programming languages implement
>>>>>> booleans using integers, it still doesn't make them the same thing.
>>>>>
>>>>> D doesn't implement booleans with integers, D has a boolean type. But D
>>>>> allows bools to implicitly cast to ints/longs.
>>>>
>>>> I'd actually argue that that's a mistake. Implicitly converting an int
>>>> to a
>>>> bool is one thing - that's useful in conditional expressions - but
>>>> converting
>>>> from bool to int is something else entirely. I see no reason to expand
>>>> that
>>>> problem into BigInt. _int_ shouldn't have it, let alone BigInt.
>>>>
>>>> - Jonathan M Davis
>>>
>>> A: "Um, so why does bool implicitly convert to int but not to BigInt?"
>>> B: "Because the language's design contains an error. It is a huge
>>> _problem_. Therefore we decided to keep it inconsistent. If you
>>> re-parenthesise your expression however, your code will compile."
>>> A: "Awesome!!"
>>
>> As I said when I closed that post, it is _impossible_ for BigInt to
>> always behave the same as int. One example:
>>
>> byte c = x & 0x7F;
>>
>> This compiles if x is an int. It doesn't compile if x is a BigInt.

This is a limitation of the language. No case can be made that this
conversion would not be desirable, and it is an issue that is not
related a lot to what is being discussed in this thread.

By the way, is this also the rationale for why BigInt and long/ulong
cannot be compared for equality?

>>
>> BigInt's job is to behave like a Euclidean integer, not to be a drop-in
>> replacement for built-in integer types.
>>


It is not any more or any less valid to build an Euclidean integer from
a residue class than from a bool.

The main problem I have with bool -> int ok, int -> BigInt ok, bool ->
BigInt NG is that it kills the transitivity of the
implicitly-converts-to relation, not that I want to use BigInt as a
drop-in replacement for int.

By the way, bool does not implicitly convert to BigInt because
std.bigint contains a bug, not because it explicitly disallows it.

Negation does not work for bool therefore it does not compile even
though it would be unreachable code.

void opAssign(T: long)(T x) // T could be bool
{
    data = cast(ulong)((x < 0) ? -x : x); // does not work for bool
    sign = (x < 0);
}


This has other interesting implications:

struct S{
    long x;
    alias x this;
    void opUnary()(){}
}

void main() {
    import std.bigint;
    S s;
    BigInt x = s; // NG!
}
December 24, 2011
Re: BigInt bool assign
On 12/24/2011 11:33 AM, Don wrote:
> On 24.12.2011 02:30, Derek wrote:
>> On Sat, 24 Dec 2011 09:19:26 +1100, bearophile
>> <bearophileHUGS@lycos.com> wrote:
>>
>>> This is why it's better to avoid casts, not requiring them in the
>>> first place, unless they are useful. In this case I think a cast
>>> introduces more danger than the risks caused by implicit bool->int
>>> conversions.
>>
>> If we assume that explicit casts are required for bool->int conversion,
>> can you show some code in which this could cause a problem?
>
> I think stuff like
> int z += x > y;
> should ideally require a cast.

What does anyone gain by adding bulky 'cast(int)' noise to their code 
that is nothing but a no-op?

> That's a crazy operation.

s/craz/nift/

>
> The problem is compatibility with ancient C code (pre-C99), where you
> may find:
>
> alias int BOOL;
>
> BOOL b = x > y;
>
> Although BOOL is typed as 'int', it really has the semantics of 'bool'.
> We have an example of this in D1's opEquals().
> I think this is reason why implicit conversion bool -> int exists.

It exists because it is handy and makes sense. Would you also want to 
ban implicit short -> int conversion?

>
> BTW, great to see you again, Derek!
December 24, 2011
Re: BigInt bool assign
On Sun, 25 Dec 2011 02:50:15 +1100, Timon Gehr <timon.gehr@gmx.ch> wrote:

>> Although BOOL is typed as 'int', it really has the semantics of 'bool'.
>> We have an example of this in D1's opEquals().
>> I think this is reason why implicit conversion bool -> int exists.
>
> It exists because it is handy and makes sense. Would you also want to  
> ban implicit short -> int conversion?

A 'short' is a type of integer, an 'int' is a type of integer, but a  
'bool' is NOT a type of integer.

One can do arithmetic with two integers but what does 'TRUTH * TRUTH'  
mean? Or what does 'FALSEHOOD - TRUTH' mean?

-- 
Derek Parnell
Melbourne, Australia
December 24, 2011
Re: BigInt bool assign
On Sat, 24 Dec 2011 21:33:33 +1100, Don <nospam@nospam.com> wrote:

>
> I think stuff like
> int z +=  x > y;
> should ideally require a cast. That's a crazy operation.

Another issue is that it is a mere convention that C uses 1 to represent  
TRUE and 0 to represent FALSE. There are some languages that use 0 for  
FALSE (all bits off) and -1 for TRUE (all bits on).


-- 
Derek Parnell
Melbourne, Australia
December 24, 2011
Re: BigInt bool assign
On 12/24/2011 05:02 PM, Derek wrote:
> On Sun, 25 Dec 2011 02:50:15 +1100, Timon Gehr <timon.gehr@gmx.ch> wrote:
>
>>> Although BOOL is typed as 'int', it really has the semantics of 'bool'.
>>> We have an example of this in D1's opEquals().
>>> I think this is reason why implicit conversion bool -> int exists.
>>
>> It exists because it is handy and makes sense. Would you also want to
>> ban implicit short -> int conversion?
>
> A 'short' is a type of integer, an 'int' is a type of integer, but a
> 'bool' is NOT a type of integer.
>
> One can do arithmetic with two integers

If so, then 'short' is not a type of integer.

> but what does 'TRUTH * TRUTH'
> mean? Or what does 'FALSEHOOD - TRUTH' mean?
>

TRUTH and FALSEHOOD are in my understanding not values, so performing 
operations on them is nonsensical.

Having the symbols {0, 1} as the boolean values is a common convention, 
even outside programming language implementations or computer 
science/digital design. So TRUE * TRUE = 1*1 = 1 and FALSE - TRUE = 0 - 
1 = -1 makes sense.
December 24, 2011
Re: BigInt bool assign
On 12/24/11 6:46 AM, Mr. Anonymous wrote:
> The D Programming Language, page 172:
> for (; n >= iter * iter; iter += 2 - (iter == 2)) { ...
> :)

And proud of every letter of it!

Andrei
December 24, 2011
Re: BigInt bool assign
On 12/24/11 9:34 AM, Derek wrote:
> Yes, I agree that this is a potential source of bugs. So what we need is
> something more explicit.
>
> double foo() { return 1.5; }
> void main() {
> int x = cast(double:int)foo();
> }
>
> Now the code is very clear about your intentions for it, and if foo() is
> later modified to return some incompatible datatype, the compile can
> alert the coder.

auto explicitCast(From, To)(From value)
{
  return cast(To) value;
}

> And to be consistent, we need to have syntax that allows a coder to
> explicitly tell the compiler to do a re-interpretation cast.

auto reinterpretCast(From, To)(From value)
if (...)
{
  return cast(To) value;
}

No need for more syntax.


Andrei
Next ›   Last »
1 2 3
Top | Discussion index | About this forum | D home