With all my respect and love to SC and it’s creators in mind:
this is a catastrophe in terms of language design: "random_string".asFloat returns 0.0!
Same way behave .asInteger etc.
This caused me today a long time looking for the reasons of unexpected behaviors in my code, having no idea why I am having a 0 somewhere shouldn’t be a zero! I just came upon the reason by accident trying every byte of my code and checking the behavior.
To understand your question more (and also some cases I was confronted with before, which I cannot remember exactly now, but I had some similar problems), what do you expect as a result of "hello".asFloat? Some of SCLANG’s behaviour with strings containing numbers is as follows:
But how can you check if a string is a valid representation of a float unless the conversion method tells you? I would expect a non-valid String to return nil (or throw) when .asFloat is called rather than 0.0, no? (Answering @smoge not @prko sorry!)
Exactly, you can’t.That’s why I’m surprise one would use it in their code without considering it can fail, that’s my point.
The language is hiding what is really happening. When you use String.asFloat, the best you get is a maybe float, and the fallback case returns zero. It is not written anywhere in the code. If you do this in Haskell, where this would be very explicit, you would need a fromMaybe 0
EDIT: ok, you can return nil but then the function won’t be String → Float anymore (it will be effectively a String → Maybe Float in practice) and then you also need to take precaution. From a language design point of view, it would be better, I think.
It definitely would be a great help if SC would throw an error (errors are nice and save your day!), as soon as a string can’t (for human readers) be converted to a floating point number! I think something like this is way more intuitive:
"11".asFloat => 11.0
"11".asInteger => 11
"11.5".asInteger => 11 (or error, because of other literals than numbers)
"11.5".asFloat => 11.5
"2e3".asFloat => 2000.0
"2e3".asInteger => 2000 (or error, because of other literals than numbers)
"hello".asFloat => Error
"hello".asInteger => Error
Yes, that would be much better. What’s the point of a conversion method if it can’t signify failure? Unfortunately, I’m not sure if we can improve this while maintaining backwards compatibility…
That is true for things like duck typing, but here we are talking about type conversions. Conversions can fail, so we need to either throw an error or return a sentinel value (e.g. nil). Returning 0.0 is just bad.
There is also the case of .asInteger. I don’t really know how to reproduce this, but I have encountered situations where value = 7.0 (in the post window) but value.asInteger = 6. For this reason I never rely on float.asInteger and always use float.round.asInteger.
Java: Java Float parseFloat() method with Examples - Javatpoint – “The parseFloat() method throws: NullPointerException - If the string passed is null. NumberFormatException - If the string passed does not hold a parsable float.”
So Java does throw an exception for a non-numeric string, but C++ does not.
I’m not disagreeing with the idea that an error would be better, but it’s worth noting that SC’s behavior does have precedent. It’s definitely arguable that it’s a bad precedent, but SC isn’t just making it up out of thin air. (The SC primitive very likely just wraps ascii-to-double = atod().)
Perhaps a different method name for asFloat with error?
(C++17 added std::from_chars (std::from_chars - cppreference.com), which returns an error code instead of throwing an exception. It also uses the C locale by default and is supposed to be the fastest among all conversion functions in the standard library.)