wren icon indicating copy to clipboard operation
wren copied to clipboard

Simplify starting bool arithmetic

Open Orcolom opened this issue 3 years ago • 20 comments

Adds Num.toCBool and Bool.toCNum

Based on discord discussion https://discord.com/channels/484796661751873554/484796759437213716/834912554450157598 and github discussions https://github.com/wren-lang/wren/pull/985#issuecomment-825587935, https://github.com/wren-lang/wren/issues/991

This would allow for instance (code sample based on the discord discussion)

var direction = Keyboard["right"].justPressed.toCNum - Keyboard["left"].justPressed.toCNum

position.x = position.x + (direction * velocity)

Orcolom avatar Apr 24 '21 12:04 Orcolom

I agree that these two methods would be a worthwhile addition to the Core library.

The only thing that’s puzzling me regarding the Num.toBool method is why you’ve decided to define arg >= 1 as true rather than the more usual arg != 0?

PureFox48 avatar Apr 24 '21 15:04 PureFox48

Totally fair, didn't really do any checks what other languages do. Threw it together quick.

This (or >= 0.5) made sense in my head, but maybe not something where we should stray from the convention

Orcolom avatar Apr 24 '21 16:04 Orcolom

what if we also add isPositive would act the same as my current implementation asbool but offset by one

then we would have asBool != 0 and isPositive >=0

Orcolom avatar Apr 24 '21 17:04 Orcolom

Well, isPositive should really be > 0 and isNonNegative >= 0.

But what’s worrying me about straying from the usual true != 0 is that the sort of idioms which C/C++ programmers are used to may not then always work.

PureFox48 avatar Apr 24 '21 17:04 PureFox48

I agree with != 0 => Bool true, and adding isPositive and isNonNegative.

cxw42 avatar Apr 24 '21 20:04 cxw42

As this and even the corrected one, I would say this is a no. It would only add more confusion about truthy/falsy values.

mhermier avatar Apr 25 '21 07:04 mhermier

I've always been surprised that the number 0 isn't regarded as falsy along with false and null. But it isn't and we're probably stuck with it as it would break a lot of code to change it now.

However, we're talking here about explicit conversions between one type and another, and I don't see any reason why we shouldn't take this opportunity to regularize the above behavior provided there is a note in the docs that 0 is regarded as false (and not truthy) for the purpose of these conversions.

I therefore remain in favor of adding Bool.ToNum and Num.toBool provided the latter treats any non-zero value as true.

Although they'd be trivial to implement, I'm not really bothered about introducing n.isPositive and n.isNonNegative, where n is a Num, because it's easier and shorter to just write n > 0 and n >= 0 respectively.

PureFox48 avatar Apr 25 '21 08:04 PureFox48

I toyed a little with the idea of fixing 0 to be falsy. And in practice it only almost only breaks loops in the tests (or the test checking the expected feature). Since null is the seed and false the end of the Iterable, in practice one implementing one should checked them explicitly anyway, and in practice for loops only needs to check for the iterator to be false. so it doesn't make much sense to maintain 0 not being falsy.

mhermier avatar Apr 25 '21 11:04 mhermier

I'd be surprised if anyone uses while (0) for an infinite loop. Most folks would use the more familiar while (1) or while (true) so I don't think that would be a big problem if it were changed

However, what worries me is more complex cases where the programmer has used a Num variable, safe in the knowledge that it'll be interpreted as truthy whatever its value may be. Those cases may be more difficult to identify and fix.

PureFox48 avatar Apr 25 '21 11:04 PureFox48

I'm honestly really confused what num truthly has to do with an explicit cast to bool? I'm missing some knowledge I think

Orcolom avatar Apr 25 '21 11:04 Orcolom

Well, I think @mhermier's point and it's a fair one, is that people might be even more confused than they already are that 0 is truthy if we regarded it for conversion purposes as false.

Be that as it may, I think we should still introduce the conversion methods and perhaps consider fixing 0 so that it is falsy to restore consistency.

PureFox48 avatar Apr 25 '21 11:04 PureFox48

@Orcolom this is math stuff related to the definition of algebra as a mathematical object. Boolean algebra and (real/imaginary) number algebra are tight coupled (and I'm not exactly sure, but the coupling can be extended to objects and null if we lower the requirement to a ring). The fact that 0 is true in wren, break the coupling the general math has, and this is quite a mess because it breaks conversions between them.

Well if we restore consistency, it would be better to restore it for good. Because I don't want to deal with differences between implicit vs explicit cast, and possibly confusion/errors that will emerge from that. And lets not forget that toBool has too be generalized for Object to, so the decision has to be clear.

mhermier avatar Apr 25 '21 13:04 mhermier

And lets not forget that toBool has too be generalized for Object to, so the decision has to be clear.

I don't think this is necessary. ISTM that the conversions we're talking about would be specific to the Num and Bool classes.

PureFox48 avatar Apr 25 '21 13:04 PureFox48

It is, in particular with generic programming if you expect Num and other Object and want to restore the usual behavior. Else you end up with something like if (a || (a is Num && a.toBool)) { ... } which is way more uglier...

mhermier avatar Apr 25 '21 13:04 mhermier

If we do need to add toBool to the Object class in the interests of generality, then I think this should be based on the truthy/falsy basis to be consistent with the other stuff in that class.

However, that doesn't prevent us from overriding it in the Num class to behave as we'd like.

PureFox48 avatar Apr 25 '21 13:04 PureFox48

Incidentally, does any one know why it was decided to make 0 a truthy value in the first place?

The docs say this is what Ruby does but I'd have thought that it was more important for Wren to follow C/C++ in this respect.

A possible difficulty is that we have two zero values for Nums: +0 and -0 which will have different bit representations. The latter has the sign bit set to 1 I believe.

PureFox48 avatar Apr 25 '21 14:04 PureFox48

To simplify iterators.

mhermier avatar Apr 25 '21 14:04 mhermier

That makes sense with false being used to signify the end of the iteration.

So, backwards compatibility aside, it wouldn't be easy to change this now.

PureFox48 avatar Apr 25 '21 16:04 PureFox48

I finished the patch for this, it is only 3 lines of C, <10 lines to fix core (that as some issues not related to the patch), 6 test suite to fix. The biggest annoyance is while iterators loop that become:

-    while (iterator = _sequence.iterate(iterator)) {
+    while ((iterator = _sequence.iterate(iterator)) != false) {

mhermier avatar Apr 25 '21 17:04 mhermier

reworked after fasly discussion at https://github.com/wren-lang/wren/issues/991

Orcolom avatar May 01 '21 17:05 Orcolom