Would this mean that this code would change from printing 'hello' to printing ''?
class foo ($x='hello') { notify { $x: }} class { 'foo': x => undef } And I guess the former behaviour would be achieved by changing it to: class foo ($x='hello') { notify { $x: }} class { 'foo': x => default } I think such a change makes sense, but on the other hand it might make it tricky to create modules that work in both versions. So you get into the situation where you have to change your puppet code at the same time as you upgrade instead of being able to prepare it for the next major version ahead of the upgrade. On 16 September 2013 02:18, Henrik Lindberg <henrik.lindb...@cloudsmith.com>wrote: > I am looking at all sorts of things for puppet 4 - one of them is how to > exorcise the special cases for puppet's undef and treating it like nil/null > in other languages. > > There is really just one special case (as noted earlier in issues) and > that is when assignment of undef takes place to a resource attribute - in > this case users want this to mean; "instead of setting this attribute to > undef, set it to the default value". > > When dealing with regular variables this does not matter, we can always > opt to not assign, but there is no way to conditionally perform an > attribute setting (not without making the entire resource expression > conditional - which explodes with permutations if there are several > variables that needs this treatment). > > e.g. for regular variables, when assignment of undef is the same as > assigning nil (and not revealing the value from an outer scope) we can > always just skip the assignment. e.g. > > In an outer scope: > $x = 'hello' > > In an inner scope: > notice $x # notices 'hello' > if $some_value != undef { > $x = $some_value > } > notice $x # notices 'hello' if $some_value was undef > > With a resource this is not possible: > > define mytype($x = 'hello') { } > mytype { 'title': > x => $some_value # always sets x > } > > without doing this: > if $some_value != undef { > mytype { 'title': > x => $some_value # always sets x > } > } > else { > mytype { 'title': } > } > > > Earlier, I proposed that we should add a new operator 'conditionally > assign attribute' - e.g. something like '?>' which means writing the > expression above like this: > > define mytype($x = 'hello') { } > mytype { 'title': > x ?> $some_value > } > > i.e., if $some_type is undef, act as if there was no assignment at all > (which will give the default value). > > I did not really like this (who needs more operators never before seen in > a language?). > > Now however, when implementing a new evaluator there is a different > possibility - we have a perfect candidate for this - the default keyword! > > In 3.x. use of default either gets evaluated to the string 'default' or > results in a parse error - which makes it difficult/impossible to use > (except in case and selector expression) as there is no difference between > the user entering the keyword default, and the string 'default' (or it just > did not work), but we can do this differently in the new evaluator! > > Proposal > -------- > The keyword undef evaluates to nil, and is a value just like any other. > When boxed to a string it becomes ''. > > The keyword default evaluates to a special value (internally the symbol > :default). When boxed to string it becomes 'default'. > > The values nil, and :default are passed around as values until they are > needed in boxed form. > > The only bit of "magic" (not very magical though) happens in the > evaluation of the attribute => operation, where assignment of :default acts > as if the assignment did not take place at all. (A user that wants to > assign this string value simply uses the string form 'default' instead of > the keyword. > > Now the example above can be written like this: > > define mytype($x = 'hello') { } > mytype { 'title': > x => $some_value ? { undef => default, default => $some_value } > } > > Or using new syntax for if, like this: > > define mytype($x = 'hello') { } > mytype { 'title': > x => if $some_value { $some_value } else { default } > } > > We could also baked this into a function 'default_if_undefined' to make it > more readable: > > define mytype($x = 'hello') { } > mytype { 'title': > x => default_if_undefined($some_**value) > } > > It is however probably a corner case used by very few and it may not be > worth adding a function for this. > > FAQ > > * Can I pass default around as a value? > Yes, it dissolves when given as the RHS value to an attribute assignment > (resource expression, resource defaults), but is otherwise a value like any > other. > > * Can I append it with +> ? > Yes, that does not dissolve it. It becomes a value in the resulting array > that then can be used in a position where it is dissolved - etc. > > * Can I place a default in an array or hash? > Yes, this works > > $a = [ 1,2,3, default] > $a = { 'x' => default, 'y' => 10 } > > * So it is only when default is the only RHS value it is dissolved? > Yes, if the RHS evaluates to default it dissolves as in these two examples: > > mytype { 'title': > x => default > } > > $a = [0, 1, default] > mytype { 'title': > x => $a[2] > } > > * Can I have a variable named $default ? > Yes, (unless we forbid keywords as variables in puppet 4 - some would like > that restriction). > > * Can I interpolate it? > Yes, well, since $default is currently an acceptable variable value we > have to decide what this means: > > "This works by ${default}" > > But since it is a literal, it is a moot point > > "This works by default" # no interpolation needed > > If it is a value, it becomes the text 'default' > > $foo = default > "This works by $foo" > > * How does the keyword default compare? > It is only equal to default. The expression 'default' == default is false. > Likewise in selectors, case, and in expressions. > > The operators <, >, <=, >= are undefined - it is neither a magnitude nor > lexical. > > Sorry, if this turned into a "mini ARM" :-) I just kept on typing... > > Comments? > > I am happy with this because: > > * $x = undef really sets $x to be undefined, not potentially defined to > something else set in an outer scope. (i.e. it is not anti-matter which is > very hard to grasp). > * It is possible to differentiate between empty string, and no value > * We do not have to translate between :undef and nil everywhere internally > * The use of default as an r-value is new and the only affected logic is > the 3x magic attribute set to default when set to undef. > > With this, one part of the complexity moves to the implementor of a > resource-type or a class, since undef can be passed as a value. This is > already required to some degree since there must be checks for empty > string. IMO the way to solve this is to offer better and simpler parameter > assertions - but that is a separate topic. > > Regards > - henrik > > -- > You received this message because you are subscribed to the Google Groups > "Puppet Developers" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to > puppet-dev+unsubscribe@**googlegroups.com<puppet-dev%2bunsubscr...@googlegroups.com> > . > To post to this group, send email to puppet-dev@googlegroups.com. > Visit this group at > http://groups.google.com/**group/puppet-dev<http://groups.google.com/group/puppet-dev> > . > For more options, visit > https://groups.google.com/**groups/opt_out<https://groups.google.com/groups/opt_out> > . > -- Erik Dalén -- You received this message because you are subscribed to the Google Groups "Puppet Developers" group. To unsubscribe from this group and stop receiving emails from it, send an email to puppet-dev+unsubscr...@googlegroups.com. To post to this group, send email to puppet-dev@googlegroups.com. Visit this group at http://groups.google.com/group/puppet-dev. For more options, visit https://groups.google.com/groups/opt_out.