Thanks Daniele, excellent feedback !
More comments below...
This is something we want to add in a 4.x version for the exact reasons
you mention - the long type specs in parameter declarations makes it
harder to read what is going on. To instead use a descriptive name is of
great value.
> By the way, if you're wondering what that Type declaration says: I
> expect a Hash, that can contain 0-* keys (I did not specify a size on
> the hash so it is allowed to be empty). Those keys must be named one of
> these four things (those in the Enum[]) and I expect all values
> associated with those keys to be Boolean, so true or false.
>
> This means people can no longer torture you and your beautiful module
> with crap like this:
>
> class { 'apt':
> purge => { 'source_file' => 'yes', 'sources_dir' => 'false',
> 'preference_file' => 'UNDEF', 'preferences_dir' => true },
> }
>
> Puppet will simply throw errors at them. The errors themselves aren't
> very informative though. Currently you get them in the form of: Expected
> parameter 'purge' to have type <the whole type definition here> but got
> <something else>. It would be nice if we could get error messages along
> the lines of: Expected parameter 'purge' to be <a more human
> description> but got <another more human description> I know that's a
> tall order, but on the list of "nice to have" I suppose.
>
We have a ticket for that. The first, simple approach only provides
meaningful output for simple cases like "excpected String, got Integer",
but it breaks down for complex types leaving it up to the user to read a
large amount of type information to find the actual diff.
We want to do a much better diff output.
> Onwards! Optional is causing me some trouble. According to the blog
> "Luckily, the type system has a type called Optional that does exactly
> what we want in this situation, it accepts something of a specific type
> or Undef."
>
> This would mean that notice(undef =~ Optional[Numeric]) should evaluate
> to true, and indeed it does:
> Notice: Scope(Class[main]): true
> Notice: Compiled catalog for nvc2542 in environment production in 0.33
> seconds
> Notice: Finished catalog run in 0.01 seconds
>
> So this should also work:
>
> class test (
> Optional[Numeric] $number = undef,
> ) {}
>
> include test
>
> However, it does not:
> Error: Expected parameter 'number' of 'Class[Test]' to have type
> Optional[Numeric], got Runtime[ruby, Symbol] on node nvc2542.
>
> I tried to change that to Variant[Numeric, Undef], even though that's
> exactly what Optional is defined as, but no dice either.. This feels
> like a bug to me, I'm hoping Henrik or Andy can shed some light on the
> situation.
>
Ah - you found a bug. Please file a ticket. We seem to have been a bit
too aggressive in removing the use of :undef.
Until it has been fixed, you could try using a Runtime[ruby, Symbol] as
the type of undef in that particular situation.
Presumably you want the key => undef to represent that you want some
sort of default value that is different from key not being set at all?
There is yet another symbolic value that be used for that, the literal
default. You can do Hash[String, Variant[Default, Integer]], and users
can pass { a => default }, or {a => 42}, and if you specify
Optional[Variant[Default, Integer]], the key can also be omitted.
Same bug as you found earlier. The evaluators notion of undef (which is
Ruby nil), is translated to the Compiler's notion of undef (Ruby symbol
:undef), but it is not translated back to nil when the type check is
made. (Same aggressive removal of :undef).
And in case you wonder, the 3x function API has different rules :-)
> At this point I'm utterly confused. It looks like I can't have Optional
> accept undef on a 'top' parameter, I can use it on a hash and initialise
> that hash with a key that is set to undef but I cannot pass in a hash
> with that same key set to undef.
>
> Maybe I've misunderstood the behaviour of Optional or something is going
> wrong in the way undef is being parsed, the Runtime[ruby, Symbol] I find
> very suspicious, but someone should look at this and figure out what's
> going on. I'm betting the answer is going to be "you're being an idiot"
> but I would really like to understand why.
>
You are not an idiot. The problem is in the bridge between new code and
old code and the messy nature of undef in the old code.
It is excellent that you found this, and I hope we can fix this in 3.7.2.
> Except for my troubles with Optional all I have to say is
> "sweeeeeeeeet". As a module maintainer, this will prevent a lot of
> headaches. If only puppet-strings could parse a human-understandable
> description of the Type annotation into the docs it generates... :).
>
Thanks Daniel for testing and sharing the experience. Much appreciated.
- henrik
--
Visit my Blog "Puppet on the Edge"
http://puppet-on-the-edge.blogspot.se/