On 2014-03-11 18:19, John Bollinger wrote:
>
>
> On Friday, October 31, 2014 8:22:36 PM UTC-5, henrik lindberg wrote:
>
> [...]
>
> Yet again someone was bit by the automatic String to Numeric conversion
> that is in Puppet (and also in --parser future).
>
>
>
> I must confess to a certain dark amusement at Puppet struggling with its
> weak-typing legacy and moving more and more in the direction of strong
> typing. Not that I am in any way happy about these difficulties, but
> I'm an old-school dinosaur, and weak typing has never seemed like such a
> great idea to me.
>
It is never a great idea to have weak / no typing. It is an even worse
idea to have all types represented as strings...
> [...]
>
> We fixed PUP-3602 by not converting strings that are floating point 0
> with exponential part and we also do not convert values that are
> floating point infinite in Ruby (e.g. 4e999 and such). This is a crutch
> though, and it is only a matter of time until someone stumbles over the
> next SURPRISE !
>
>
>
> Indeed so. If you rely on heuristics to choose behavior then you have
> to accept that sometimes the wrong behavior will be chosen. In this
> case, it is purely a guess that a string starting with "0e[digit]" is
> not meant to be interpreted as a number.
>
Yes, this was a bit of a panic fix. It really sucks.
> The best cure is naturally to never do String to numeric conversion.
>
>
>
> What about numeric to string conversion? I guess Puppet doesn't do that
> automatically now, so maybe this isn't the time to start, but that /is/
> an alternative approach to mixed string/number comparison.
>
True, 4.0.0 will not do numeric to string automatically (because of
radix, precision and floating point formatting). I do not see that
coming back.
> And
> we wonder what people feel about that. Should we go for this in Puppet
> 4.0.0 (and have a 3.7.4 release as the last of the 3x series where this
> behavior is implemented when using --parser future).
>
>
>
> I think avoiding automatic string to numeric conversion is consistent
> with forbidding bare strings starting with a digit..
Good point.
> It would be a lot
> better, though, if in the context of the manifest it were clearer which
> expressions are strings and which are numeric. That's no problem for
> literals, of course, but none of this is interesting in the case where
> all the values involved are literals. I (think I) understand that with
> the P4 parser and evaluator it will be possible to declare types
> specifically enough to address that issue, but it is also my
> understanding that expressions won't /necessarily/ have formal types
> specific enough for that.
>
It is a bit difficult since operators are overloaded on type. The good
part is that if we stop transforming strings to numbers there will be
errors for arithmetic expressions.
The bad part is that ==, != cannot raise errors (since a string is
simply not equal to a number). Currently comparisons order all numbers
to be smaller than all strings. We could change those to instead error
if the types are not comparable to each other.
> It is highly desirable to give manifest authors sufficient control over
> conversions to avoid unwanted ones, but it is not altogether clear to me
> whether the best approach is to nix all automatic string-to-number
> conversions. A lot of existing manifests rely on such conversions,
> since they used to be the only alternative. P4 is at liberty to break
> backward compatibility, but maybe a little less breakage would be wiser?
>
While I am not so worried about the logic in the manifests themselves.
There has not been that many problems reported with respect to the
conversion in the other direction. For resource attributes however the
situation is worse since there are many types out there where it is
unknown how they deal with data types, what sort of munging / processing
they do of strings/numbers etc.
This would be the primary reason (IMO) to not do this until resource
types can type their parameters. (Since typed parameters direct
serialization, and there is no longer a question if a serialized "42"
should be a number or a string).
> * Add === operator to compare both type and value. This is a slippery
> slope since we probably want Integer and Float to compare equal - say
> 0.0 and 0. It adds yet another operator, and we have to decide what
> case, selector and in should use since there is no way to specify if
> one
> or the other should be used.
>
>
>
> I agree that as proposed, the '===' operator would be troublesome.
> There is always the alternative, though, of keeping '==' as it is, and
> making '===' simply perform a comparison without string/number
> conversion. I think 'case', selector, and 'in' behavior are
> collectively a red herring, though: if '===' were adopted in any form
> then 'case', selector, and 'in' behavior would still be whatever is
> specified for them, whether that's their current behavior or a variant
> one based on '==='. There is no requirement that that behavior be
> selectable between different senses of equality.
>
> I'm not necessarily advocating that solution, but I think it's
> appropriate to take a careful, unbiased look at all the alternatives.
> I'm not certain they're all on the table, yet. For example, how about this:
>
> * The value of an expression may be converted to a different type only
> to the extent that the target type is consistent with the expression's
> /formal/ type.
>
> For example, if a class parameter is declared to be type String then
> it's value cannot be automatically converted to Numeric or any of its
> subtypes, but if it is type Scalar or Object and happens to /contain/ a
> string, then the string value /can/ be automatically converted to a
> number (a Float, for instance). That could yield backward compatibility
> for existing manifests that do not declare types, while still allowing
> authors to control the allowed conversions.
>
Interesting idea, but problematic to implement and having good
performance. Now the type of an expression is encoded in the resulting
instance / value. Adding the more advanced "declared type narrows
conversion", I think it is required to also keep track of the declared
type of every (intermediate) value. All functions must declare their
return type etc. Since no functions do that now, we would basically
always operate on the Any type, and all conversions would be allowed.
In general I think narrowing the conversions to declared type would be
difficult. It could possibly be done when passing arguments to
functions, defined types, or parameterized classes. Currently it only
checks for type compliance, and I don't have any immediate ideas for how
to specify type conversion except something like specifying a lambda per
parameter to do type conversion, or special type conversion functions
that apply in different scopes. I think that adds complexity that is
more difficult to deal with than explicit conversion (i.e. accept a
broader type, then convert/assert inside the body of the construct).