On Sunday, July 6, 2014 8:26:28 PM UTC-5, henrik lindberg wrote: > > Thank you everyone that commented on the first RFC for Resource Defaults > (and Collection) - some very good ideas came up. I am creating a new > thread because I wanted to take the Collection part in a separate > discussion (honestly I would like to burn the entire implementation - > but that is separate topic), and I want to present some new ideas about > defaults triggered by David Schmitts idea about defaults applicable to > only a resource body. > > Let me back up and first describe a problem we have in the grammar. > > The egrammar (as well as the current grammar in 3x) tries to be helpful > by recognizing certain combinations as illegal (an override that is > virtual or exported), a resource default or override cannot specify a > title. This unfortunately means that the grammar has to recognize > sequences of tokens that makes this grammar ambiguous and it has to be > solved via operator precedence tricks (that makes the problem show up as > other corner cases of the grammar).
I agree that that is a problem. Are you saying that the 3.x grammar also has such ambiguities, or just that it also rejects some token sequences (as any grammar must do)? > (This is a classic mistake of trying > to implement too much semantics in the grammar / parser). > > So... > > What if we simply made the three resource expressions (create resource, > set resource defaults, an resource override) have exactly the same > grammar, and push of validation to the static validation that takes > place and the runtime. > > Basically the grammar would be (I am cheating just a little here to > avoid irrelevant details): > > ResourceExpression > : At? left_expr = Expression '{' ResourceBodies ';'? '}' > ; > > ResourceBodies > : ResourceBody (';' ResourceBody)* > ; > > ResourceBody > : title = Expression ':' AttributeOperations ','? > ; > > AttributeOperations > : AttributeOperation (',' AttributeOperation)* > ; > > AttributeOperation > : AttributeName ('=>' | '+>') Expression > > AttributeName > : NAME | KeywordsAcceptableAsAttributeName > ; > > # Details here irrelevant, meaning is: virtual or exported resource > # AT is the '@' token > At > : AT > | AT AT > | ATAT > ; > > So, how are the three kinds expressed? Notice that a title is required > for each ResourceBody. So we are basically going to handle different > combinations of left_expr and titles. We simply evaluate the left_expr > at runtime and treat the combinations of the *resulting* type and type > of title: > > If left (result) is a String, it must be the name of a Resource Type. > The title works as it does now in 3x. In addition the title (of one > resource body) may be Default, which sets the defaults for this resource > expression only (all bodies in the same resource expression) - i.e. > "Schmitt style". > > notify { hi: message => 'hello there' } > > file { > default: > mode => '0331', > owner => 'weird'; > '/tmp:foo': > content => 'content 1' > } > > If the left is the keyword 'class', it works the same way as for when > the left is a String but defaults can now only set defaults for meta > parameters since there are no other attributes that work safely across > all classes. (Yes you can do this today with Class { } in 3x) > > class { 'a::b': param => value } > class { default: audit => true } > > If the left is Type[CatalogEntry] (i.e. a resource or class reference), > the meaning changes to either a default or an override. I'm not fully up to speed on the type system, but surely if the left side evaluates to a resource or class *reference* then the statement can only be an override. Right? For it to express resource defaults, the left side must evaluate to a type -- either Class or a resource type. > An example is > probably easier that lots of words to describe this: > > Define the defaults for all instances of the resource type Notify: > > Notify { default: > message => 'the default message' > } > > Override the message for the notify resource hi. > > Notify { hi: > message => 'ciao' > } > > If the left type is instance specific it is now an error (since a title > followed by ':' is required to create a less ambiguous grammar) - if we > allowed this, a user could write: > > Notify[hi] { bye: message => 'adieu' } > > we allow a very odd statement (and the reason why resource overrides > currently does not allow a title in its "resource body"). So, an error > for this case. > I tried hard to not like this, but then I recognized how congruent it is -- or could be -- with one of my pet ideas: resource constraints. Felix implemented part of that idea, but as I understand it, he handled only the diagnostic part (recognizing whether constraints were satisfied) and not the prescriptive part (updating the catalog, if possible, to ensure that declared constraints *are* satisfied). I don't much like the idea of "overriding" resource declarations as such, but it's not such a big leap to reposition that as simply declaring additional requirements (i.e. constraints) on resources that (may) be declared elsewhere. We get the rest of the way to a limited form of prescriptive constraints by collapsing this variety of resource overrides with resource declarations. In other words, consider these two expressions: file { '/tmp/hello': ensure => 'file' } File { '/tmp/hello': ensure => 'file' } What if they meant exactly the same thing? Specifically, what if they meant "there must be a resource in the catalog of type File and name '/tmp/hello', having the value 'file' for its 'ensure' property"? Either one would then insert such a resource into the catalog if necessary, and afterward attempt to set the (then) existing resource's 'ensure' parameter. I say "attempt to set" the existing resource's parameter, because I think we still need to forbid modifying a value that was set (to a different value) somewhere else. And that's more complicated than just checking for undef, because it may be that undef is itself the intentionally assigned parameter value, so that it would be an error to change it. It also might need to be more permissive for subclasses and collectors. We could go farther with that. If it seems wasteful to have two different forms of the same statement, then we could apply additional semantics to one or the other. For example, perhaps the lowercase form could implicitly declare all unmentioned parameters as undef, with the effect that they could not be overridden to anything different. I don't know whether that would be useful, or whether there is some other behavior that would be more useful. Perhaps it would be best to just let the two forms be equivalent, or maybe even to deprecate one. Anyway, a few corner cases exist. A +> is only allowed if it is a > default or override expression. +> is a bit of a dark horse in the regime of overrides, as modifying a previously-declared parameter value is inherent in its design. On the other hand, it is currently useful for overrides only in subclasses and collectors, where modifying a declared value is considered acceptable. I don't think it's a major issue that evaluating a statement containing a plussignment may yield an error, as long as the meaning of the statement is not itself in question. Do you like these ideas? Is it worth trying to make this work to try it > in practice? (it will take 1-2 days for the implementation, and a bit > more to fix all breaking tests). > As I said before, I tried to dislike them, but I like them despite myself. Especially if you're willing to accept my extension. > > My own main issue with the idea is that it makes code backwards > incompatible; you cannot write a manifest that uses defaults and > overrides in a way that works both in 3.x and 4.x. (Or, I have not > figured out a way yet at least). > > That's the main reason I tried to dislike the idea, and it's not negligible. It seems like the best alternative for that would be to select an alternative syntax for type expressions that cannot be confused with resource references. Doing so would remove some of the reason for the above idea, but would not render it moot. -- 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 view this discussion on the web visit https://groups.google.com/d/msgid/puppet-dev/015bddfe-684b-4ceb-b09b-6f3f2550f4b4%40googlegroups.com. For more options, visit https://groups.google.com/d/optout.