RFC - introduction of self keyword

13 views
Skip to first unread message

Dan Bode

unread,
Feb 1, 2011, 5:02:15 PM2/1/11
to puppe...@googlegroups.com
Hi all,

I wanted to open the feature request http://projects.puppetlabs.com/issues/5824 for discussion.

I like to specify all dependencies not defined within the enclosed scope using the new relationship syntax.

This leads to nice clean error messages if the required resources have not been declared.

class foo (
   $bar => 'baz'
) {
  Class['foo']->Class['super-ninja-app']
  .. resources and what-not
}

I often use this syntax to specify external dependencies of the class itself. I am starting to use this pattern *a lot*

Having to specify
 
Class['foo']-> within class foo { }

in less than optimal for two reasons:
  1. more characters
  2. if the name of the class changes, then the reference to the class also needs to change

I would like to introduce the 'self' keyword to be used in this situation.

-Dan

Ian Ward Comfort

unread,
Feb 1, 2011, 5:30:53 PM2/1/11
to puppe...@googlegroups.com

I like this idea in theory. (I limit my statement only because we're still in the process of migrating to 2.6.x here, and my ideas about parameterized classes and how I'd like to use them are still purely theoretical.) Since the longhand syntax is already permitted, providing "Self" as shorthand doesn't seem too dangerous -- modulo keyword namespace concerns, I guess.

I'm curious to hear Nigel's misgivings, though, in case I'm missing something.

--
Ian Ward Comfort <icom...@stanford.edu>
Systems Team Lead, Academic Computing Services, Stanford University

Nigel Kersten

unread,
Feb 1, 2011, 6:24:30 PM2/1/11
to puppe...@googlegroups.com
My misgivings are blurry, but center around complexifying what was meant to be a "simple DSL".



Ian Ward Comfort

unread,
Feb 1, 2011, 6:43:09 PM2/1/11
to puppe...@googlegroups.com

I'm definitely sympathetic to that concern. In a sense, the proposal is analogous to #4885, though (allowing simple specification of module paths with ~). Would it seem less dangerous if the syntax were different? (And is there anything that can be done with "Self" that can't already be done with Class[foo] inside the foo class?)

Daniel Pittman

unread,
Feb 1, 2011, 6:49:12 PM2/1/11
to puppe...@googlegroups.com
On Tue, Feb 1, 2011 at 15:24, Nigel Kersten <ni...@puppetlabs.com> wrote:
> On Tue, Feb 1, 2011 at 2:30 PM, Ian Ward Comfort <icom...@stanford.edu> wrote:
>> On 1 Feb 2011, at 2:02 PM, Dan Bode wrote:
>> > I wanted to open the feature request
>> > http://projects.puppetlabs.com/issues/5824 for discussion.

[...]

>> > I would like to introduce the 'self' keyword to be used in this
>> > situation.
>>
>> I like this idea in theory.  (I limit my statement only because we're
>> still in the process of migrating to 2.6.x here, and my ideas about
>> parameterized classes and how I'd like to use them are still purely
>> theoretical.)  Since the longhand syntax is already permitted, providing
>> "Self" as shorthand doesn't seem too dangerous -- modulo keyword namespace
>> concerns, I guess.
>>
>> I'm curious to hear Nigel's misgivings, though, in case I'm missing
>> something.
>
> My misgivings are blurry, but center around complexifying what was meant to
> be a "simple DSL".

For what it is worth, I could see this being a way out of the morass
of referring to the attributes of the declaration rather than the
enclosing scope, making the language more useful:

define foo () {
notify { "$name is from my parent": }
notify { "$self::name is from me": }
}
foo { "bar": }

bar is from my parent
foo is from me

(...or perhaps backwards :)

Regards,
Daniel
--
⎋ Puppet Labs Developer – http://puppetlabs.com
✉ Daniel Pittman <dan...@puppetlabs.com>
✆ Contact me via gtalk, email, or phone: +1 (877) 575-9775
♲ Made with 100 percent post-consumer electrons

Michael Stahnke

unread,
Feb 1, 2011, 10:50:08 PM2/1/11
to puppe...@googlegroups.com
I think I am echoing Nigel's concerns, but if the primary audience of
puppet and the people creating configs are system admins, the concept
of self may be foreign. I agree it's not super complicated, but still
could make the barrier to understanding slightly higher.

stahnma

Luke Kanies

unread,
Feb 2, 2011, 1:47:41 AM2/2/11
to puppe...@googlegroups.com
I think a far better solution is to support static declaration of class dependencies:

class foo requires otherclass {...}

or

class foo requires Yay[boo] {...}

Although I expect it would be an antipattern for classes to require things other than classes and thus maybe shouldn't be supported.

This would get you what you want, plus make it really easy to build a graph of classes and their relationships.  Mmmm, graphs.

If that were added, would you still want the 'self' keyword?


--
Should I say "I believe in physics", or "I know that physics is true"?
-- Ludwig Wittgenstein, On Certainty, 602.
---------------------------------------------------------------------
Luke Kanies -|- http://puppetlabs.com -|- +1(615)594-8199


Luke Kanies

unread,
Feb 2, 2011, 1:48:09 AM2/2/11
to puppe...@googlegroups.com

Isn't the fix for that to make Puppet's language lexical rather than dynamic?

--
Venter's First Law:
Discoveries made in a field by some one from another discipline will
always be upsetting to the majority of those inside.

donavan

unread,
Feb 2, 2011, 2:08:00 AM2/2/11
to Puppet Developers
On Feb 1, 2:02 pm, Dan Bode <d...@puppetlabs.com> wrote:
> Hi all,
>
> I wanted to open the feature requesthttp://projects.puppetlabs.com/issues/5824for discussion.

I suppose I would echo the general complexity concern about the
'simple' puppet DSL. I see the use case, but the problem scope seems
very limited in comparison to another expansion of the DSL. Does this
really solve any problem besides changing internal references when you
change a class name?

And on a vaguely related note:
Does Class[foo]->Class[bar] still create a many to many set of
relationships between all resources in those two classes?
Is the puppet DSL really such a simple DSL anymore? We keep adding
complex functionality to the 'basic' puppet DSL instead of the
'advanced' Ruby DSL.

Dean Wilson

unread,
Feb 2, 2011, 2:43:09 AM2/2/11
to puppe...@googlegroups.com
On 2 February 2011 06:47, Luke Kanies <lu...@puppetlabs.com> wrote:

> I think a far better solution is to support static declaration of class
> dependencies:

> class foo requires otherclass {...}
> or
> class foo requires Yay[boo] {...}

I like this syntax. I'm also fine with it only allowing classes to be
specified as the dependency.

Dean
--
Dean Wilson               http://www.unixdaemon.net
Profanity is the one language all programmers understand
--- Anon

Dan Bode

unread,
Feb 2, 2011, 3:05:58 AM2/2/11
to puppe...@googlegroups.com
On Tue, Feb 1, 2011 at 10:47 PM, Luke Kanies <lu...@puppetlabs.com> wrote:
On Feb 1, 2011, at 2:02 PM, Dan Bode wrote:

Hi all,

I wanted to open the feature request http://projects.puppetlabs.com/issues/5824 for discussion.

I like to specify all dependencies not defined within the enclosed scope using the new relationship syntax.

This leads to nice clean error messages if the required resources have not been declared.

class foo (
   $bar => 'baz'
) {
  Class['foo']->Class['super-ninja-app']
  .. resources and what-not
}

I often use this syntax to specify external dependencies of the class itself. I am starting to use this pattern *a lot*

Having to specify
 
Class['foo']-> within class foo { }

in less than optimal for two reasons:
  1. more characters
  2. if the name of the class changes, then the reference to the class also needs to change

I would like to introduce the 'self' keyword to be used in this situation.

I think a far better solution is to support static declaration of class dependencies:

class foo requires otherclass {...}

or

class foo requires Yay[boo] {...}

that seems like it could be messy with inheritance as well.

class foo requires Yay[boo], Yah[blah] inherits bar {...}

 
Although I expect it would be an antipattern for classes to require things other than classes and thus maybe shouldn't be supported.

I would rather follow the basic principal of being flexible as we can. I am starting to get suspicious anytime anyone uses the word anti-pattern.

 
This would get you what you want, plus make it really easy to build a graph of classes and their relationships.  Mmmm, graphs.

If that were added, would you still want the 'self' keyword?

that would suffice.

 

--
Should I say "I believe in physics", or "I know that physics is true"?
-- Ludwig Wittgenstein, On Certainty, 602.
---------------------------------------------------------------------
Luke Kanies -|- http://puppetlabs.com -|- +1(615)594-8199


--
You received this message because you are subscribed to the Google Groups "Puppet Developers" group.
To post to this group, send email to puppe...@googlegroups.com.
To unsubscribe from this group, send email to puppet-dev+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/puppet-dev?hl=en.

Trevor Vaughan

unread,
Feb 2, 2011, 9:40:03 AM2/2/11
to puppe...@googlegroups.com
This was pretty much the reply that I was forming in my head.

I'm seriously concerned about the many-to-many graph explosion that
happens with requiring a class.

It makes this concept work well for very small configurations but I've
officially listed it as a code smell for any internal development due
to both server and client death on complex graphs.

Trevor

> --
> You received this message because you are subscribed to the Google Groups "Puppet Developers" group.
> To post to this group, send email to puppe...@googlegroups.com.
> To unsubscribe from this group, send email to puppet-dev+...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/puppet-dev?hl=en.
>
>

--
Trevor Vaughan
Vice President, Onyx Point, Inc
(410) 541-6699
tvau...@onyxpoint.com

-- This account not approved for unencrypted proprietary information --

Luke Kanies

unread,
Feb 2, 2011, 9:54:35 AM2/2/11
to puppe...@googlegroups.com

It does today, but we should be fixing that this year. All of the groundwork is laid, now we just need to make the actual change. I've got a branch out that gets us 95% of the way there, but I couldn't get it done in time for 2.6, so it's gotten a bit musty.

I don't know if it'll be in 2.7, but definitely this year.

--
It is curious that physical courage should be so common in the world and
moral courage so rare. -- Mark Twain

Luke Kanies

unread,
Feb 2, 2011, 10:02:48 AM2/2/11
to puppe...@googlegroups.com
It could certainly get messy, but I don't think this is that bad, especially if we stick to just requiring classes:

  class foo requires [boo, blah] inherits bar {...}

Although I expect it would be an antipattern for classes to require things other than classes and thus maybe shouldn't be supported.

I would rather follow the basic principal of being flexible as we can. I am starting to get suspicious anytime anyone uses the word anti-pattern.

Heh. :)

Well, one of the points of the DSL is to be painfully simple.

This would get you what you want, plus make it really easy to build a graph of classes and their relationships.  Mmmm, graphs.

If that were added, would you still want the 'self' keyword?

that would suffice.

Great.


--
Consistency requires you to be as ignorant today as you were a year
ago. -- Bernard Berenson

Luke Kanies

unread,
Feb 2, 2011, 10:03:34 AM2/2/11
to puppe...@googlegroups.com
On Feb 2, 2011, at 6:40 AM, Trevor Vaughan wrote:

> This was pretty much the reply that I was forming in my head.
>
> I'm seriously concerned about the many-to-many graph explosion that
> happens with requiring a class.
>
> It makes this concept work well for very small configurations but I've
> officially listed it as a code smell for any internal development due
> to both server and client death on complex graphs.

This is obviously a separate problem, but I agree, we need to get this fixed.

--
Opportunity is missed by most people because it is dressed in overalls
and looks like work. -- Thomas A. Edison

James Turnbull

unread,
Feb 2, 2011, 11:14:18 AM2/2/11
to puppe...@googlegroups.com
Dean Wilson wrote:
> On 2 February 2011 06:47, Luke Kanies <lu...@puppetlabs.com> wrote:
>
>> I think a far better solution is to support static declaration of class
>> dependencies:
>
>> class foo requires otherclass {...}
>> or
>> class foo requires Yay[boo] {...}
>
> I like this syntax. I'm also fine with it only allowing classes to be
> specified as the dependency.

Ditto. I'm with Dean.

James

--
James Turnbull
Puppet Labs
1-503-734-8571

Daniel Pittman

unread,
Feb 2, 2011, 12:26:30 PM2/2/11
to puppe...@googlegroups.com

Well, one fix. It means an extra temporary variable to expose the name on the define vs the name of the resource in properties of the resource, but that would also be OK by me.

Regards,
    Daniel
--
Puppet Labs Developer –http://puppetlabs.com
Daniel Pittman <dan...@puppetlabs.com>
Contact me via gtalk, email, or phone: +1 (877) 575-9775

Sent from a mobile device. Please forgive me if this is briefer than usual.

Thomas Bellman

unread,
Feb 3, 2011, 4:40:36 AM2/3/11
to puppe...@googlegroups.com
On 2011-02-02 16:02, Luke Kanies wrote:

> On Feb 2, 2011, at 12:05 AM, Dan Bode wrote:

>> class foo requires Yay[boo], Yah[blah] inherits bar {...}
>
> It could certainly get messy, but I don't think this is that bad, especially
> if we stick to just requiring classes:
>
> class foo requires [boo, blah] inherits bar {...}

What about the already existing syntax:

class foo inherits bar {
require boo, blah
...
}

Is the require() function that unloved?


/Bellman

Luke Kanies

unread,
Feb 3, 2011, 12:59:15 PM2/3/11
to puppe...@googlegroups.com

The problem with it is that it's compile time, not parse time - meaning that you couldn't do static class dependency analysis without compiling all of the classes, and even then you wouldn't know if a given class always has that list of dependencies, or only for that one host.

That make sense?

--
The chief lesson I have learned in a long life is that the only way to
make a man trustworthy is to trust him; and the surest way to make him
untrustworthy is to distrust him and show your distrust.
-- Henry L. Stimson

Ian Ward Comfort

unread,
Feb 3, 2011, 3:12:16 PM2/3/11
to puppe...@googlegroups.com
On 3 Feb 2011, at 9:59 AM, Luke Kanies wrote:
> On Feb 3, 2011, at 1:40 AM, Thomas Bellman wrote:
>> On 2011-02-02 16:02, Luke Kanies wrote:
>>> On Feb 2, 2011, at 12:05 AM, Dan Bode wrote:
>>>> class foo requires Yay[boo], Yah[blah] inherits bar {...}
>>>
>>> It could certainly get messy, but I don't think this is that bad, especially
>>> if we stick to just requiring classes:
>>>
>>> class foo requires [boo, blah] inherits bar {...}
>>
>> What about the already existing syntax:
>>
>> class foo inherits bar {
>> require boo, blah
>> ...
>> }
>>
>> Is the require() function that unloved?
>
> The problem with it is that it's compile time, not parse time - meaning that you couldn't do static class dependency analysis without compiling all of the classes, and even then you wouldn't know if a given class always has that list of dependencies, or only for that one host.
>
> That make sense?

The require function also includes the named classes without parameters, correct?

Luke Kanies

unread,
Feb 3, 2011, 4:38:02 PM2/3/11
to puppe...@googlegroups.com
On Feb 3, 2011, at 12:12 PM, Ian Ward Comfort wrote:

> On 3 Feb 2011, at 9:59 AM, Luke Kanies wrote:
>> On Feb 3, 2011, at 1:40 AM, Thomas Bellman wrote:
>>> On 2011-02-02 16:02, Luke Kanies wrote:
>>>> On Feb 2, 2011, at 12:05 AM, Dan Bode wrote:
>>>>> class foo requires Yay[boo], Yah[blah] inherits bar {...}
>>>>
>>>> It could certainly get messy, but I don't think this is that bad, especially
>>>> if we stick to just requiring classes:
>>>>
>>>> class foo requires [boo, blah] inherits bar {...}
>>>
>>> What about the already existing syntax:
>>>
>>> class foo inherits bar {
>>> require boo, blah
>>> ...
>>> }
>>>
>>> Is the require() function that unloved?
>>
>> The problem with it is that it's compile time, not parse time - meaning that you couldn't do static class dependency analysis without compiling all of the classes, and even then you wouldn't know if a given class always has that list of dependencies, or only for that one host.
>>
>> That make sense?
>
> The require function also includes the named classes without parameters, correct?

I don't think I understand your question; can you elaborate?

Ian Ward Comfort

unread,
Feb 3, 2011, 4:57:48 PM2/3/11
to puppe...@googlegroups.com
On 3 Feb 2011, at 1:38 PM, Luke Kanies wrote:
> On Feb 3, 2011, at 12:12 PM, Ian Ward Comfort wrote:
>> On 3 Feb 2011, at 9:59 AM, Luke Kanies wrote:
>>> On Feb 3, 2011, at 1:40 AM, Thomas Bellman wrote:
>>>> What about the already existing syntax:
>>>>
>>>> class foo inherits bar {
>>>> require boo, blah
>>>> ...
>>>> }
>>>>
>>>> Is the require() function that unloved?
>>>
>>> The problem with it is that it's compile time, not parse time - meaning that you couldn't do static class dependency analysis without compiling all of the classes, and even then you wouldn't know if a given class always has that list of dependencies, or only for that one host.
>>>
>>> That make sense?
>>
>> The require function also includes the named classes without parameters, correct?
>
> I don't think I understand your question; can you elaborate?

My understanding (still theoretical, since we're 0.25 here) is that "require foo" is just like "include foo", with an additional dependency between the enclosing class and the foo class. You only get the functionality of "include"; you can't give parameters to foo if it is a parameterized class ("class foo { param => value }").

To my mind, that's the advantage of Dan's proposed "Self" keyword -- you can use it to just set up the dependency, so you can declare the other class or resource elsewhere with whatever parameters you like. (You can also put it on the LHS of the -> operator, whereas "require" or "requires" can only put the class you're defining on the RHS, so to speak.)

I'm sympathetic to the concerns voiced so far, though. "Self" seems like just syntactic sugar, since you can already do stuff like Dan's first snippet in #5824. I'm not sure if that's a point for or against, though. :)

Luke Kanies

unread,
Feb 4, 2011, 1:17:00 AM2/4/11
to puppe...@googlegroups.com
On Feb 3, 2011, at 1:57 PM, Ian Ward Comfort wrote:

> On 3 Feb 2011, at 1:38 PM, Luke Kanies wrote:
>> On Feb 3, 2011, at 12:12 PM, Ian Ward Comfort wrote:
>>> On 3 Feb 2011, at 9:59 AM, Luke Kanies wrote:
>>>> On Feb 3, 2011, at 1:40 AM, Thomas Bellman wrote:
>>>>> What about the already existing syntax:
>>>>>
>>>>> class foo inherits bar {
>>>>> require boo, blah
>>>>> ...
>>>>> }
>>>>>
>>>>> Is the require() function that unloved?
>>>>
>>>> The problem with it is that it's compile time, not parse time - meaning that you couldn't do static class dependency analysis without compiling all of the classes, and even then you wouldn't know if a given class always has that list of dependencies, or only for that one host.
>>>>
>>>> That make sense?
>>>
>>> The require function also includes the named classes without parameters, correct?
>>
>> I don't think I understand your question; can you elaborate?
>
> My understanding (still theoretical, since we're 0.25 here) is that "require foo" is just like "include foo", with an additional dependency between the enclosing class and the foo class. You only get the functionality of "include"; you can't give parameters to foo if it is a parameterized class ("class foo { param => value }").

That is correct.

> To my mind, that's the advantage of Dan's proposed "Self" keyword -- you can use it to just set up the dependency, so you can declare the other class or resource elsewhere with whatever parameters you like. (You can also put it on the LHS of the -> operator, whereas "require" or "requires" can only put the class you're defining on the RHS, so to speak.)

That's just as true here - the dependency would have to have been declared elsewhere for my proposal to work.

Ideally, though, you'd use an ENC that declared all of these classes, and it would be smart enough to use the ResourceType REST API to query Puppet and ask what parameters are needed and what dependences exist for a given class. :)

> I'm sympathetic to the concerns voiced so far, though. "Self" seems like just syntactic sugar, since you can already do stuff like Dan's first snippet in #5824. I'm not sure if that's a point for or against, though. :)

I think it's unnecessarily complex at this point, especially since there are better syntaxes that provide a lot more function.


--
Good judgment comes from experience, and experience comes from bad
judgment. --Barry LePatner

Thomas Bellman

unread,
Feb 4, 2011, 10:40:06 AM2/4/11
to puppe...@googlegroups.com
On 2011-02-03 18:59, Luke Kanies wrote:

> On Feb 3, 2011, at 1:40 AM, Thomas Bellman wrote:

>> Is the require() function that unloved?

> The problem with it is that it's compile time, not parse time - meaning
> that you couldn't do static class dependency analysis without compiling
> all of the classes, and even then you wouldn't know if a given class
> always has that list of dependencies, or only for that one host.

> That make sense?

Well, I understand where you're coming from, but I disagree. :-) To
do such an analysis statically, you have three things against you:

1. The require() function can be replaced/overridden with a user-
defined function.
2. The arguments to require() are not necessarily constant strings.
3. The call to require() can be inside a conditional.

You can easily detect the latter two points, and provide the static
analysis when they are not the case. Anyone doing dynamic require:s
would be unable to use your syntax and would be forced to use the
require() function anyway, so you won't lose any cases there.

The first point is more difficult, although an analyzer could simply
*assume* that the standard definition of require() is used, and you
would overdetect dependencies in those very few cases where someone
has another require() function.

So, it just becomes a tiny bit more difficult to do such an analysis,
but it shouldn't be very much.

Adding another syntax for specifying relationships, one that can't do
anything the already existing syntaxes can do, seems to me to not give
any real added value. It just makes the language larger and more
unweildly and difficult to learn.


/Bellman

Luke Kanies

unread,
Feb 10, 2011, 7:11:25 PM2/10/11
to puppe...@googlegroups.com

How about we split down the middle - you add the analysis to the current system to rely on require, and I'll merge it. :)

You do make good points, and you could have a reasonable analysis done on the current state, but it would always get complicated. E.g, the analysis would need to know about nested classes and conditionals. Also, it wouldn't work for classes written using the ruby DSL (although we could add a separate syntax there).

And, generally, I far prefer the model where things like this are just statically declared if at all possible. I could quite possibly be wrong on this, but it's my instincts are pushing strongly for static declaration.

--
A conservative is a man who believes that nothing should be done for
the first time. --Alfred E. Wiggam

Reply all
Reply to author
Forward
0 new messages