YAML and initializers

Here’s a thought question for you. If you read the subject line, you
already know the answer.

A user-defined class has an initializer. When/how would you ever create
an instance of that class without calling the initializer?

Hmm.

The answer, of course, is when you load it from a marshaled format such
as YAML.

This brings me to my question.

When entities have default values in the constructor, we can omit them
when calling #new.

I’d like to be able to omit these in YAML also. (I can omit them now,
of course, but they get nil values).

Here’s some code in case it clarifies a little.

require “yaml”

class MyClass
def initialize(a,b,c=5)
@alpha, @beta, @gamma = a,b,c
end
end

foo = MyClass.new(3,4)

y1 = foo.to_yaml
y2 = y1.split("\n").find_all {|x| x !~ /gamma/ }.join("\n")

y2 has no gamma

f2 = YAML.load(y2)
p f2

I’d like f2 to have a ‘5’ for @gamma

Is this doable with add_domain_type or something? This is beyond my
current knowledge of YAML.

A part of me wishes that YAML could somehow be smart enough to call
the constructor, maybe with a special call like ‘construct’ instead
of ‘load’ – but there are likely ramifications I haven’t thought of.

Thanks,
Hal

Good discussion, Hal. I’ve been really rethinking the YAML+Ruby typing
mechanism, so this is a perfect time for this. Right on.

Hal Fulton wrote:

When entities have default values in the constructor, we can omit them
when calling #new.

I’d like to be able to omit these in YAML also. (I can omit them now,
of course, but they get nil values).

So, if I understand you correctly, you use default values in the
constructor to enforce default values for object properties. In the
case below:

require “yaml”

class MyClass
def initialize(a,b,c=5)
@alpha, @beta, @gamma = a,b,c
end
end

…the use of c=5 is a way of ensuring that 5 is the default value for
@gamma.

A part of me wishes that YAML could somehow be smart enough to call
the constructor, maybe with a special call like ‘construct’ instead
of ‘load’ – but there are likely ramifications I haven’t thought of.

In the case of the above constructor, it would be impossible for YAML to
know in what order to pass the three parameters and I don’t have any
ideas for making the YAML loader work with the constructor.

I think the best solution for this would be akin to
Object#initialize_copy. In fact, it seems like YAML could call
Object#initialize_copy with the new object, should an
Object#initialize_copy method exist. Yeh?

Yes, you can also do this with a typing callback:

YAML::add_domain_type( “hypermetrics.com,2004”, “MyClass” ) do
>type, val|
val[‘gamma’] ||= 5
YAML::object_maker( MyClass, val )
end

YAML::load( <<EOY )
— !hypermetrics.com,2004/MyClass
alpha: 10
beta: 20
EOY
#=> #<MyClass:0x82418c0 @alpha=10, @gamma=5, @beta=30>

_why

why the lucky stiff wrote:

Good discussion, Hal. I’ve been really rethinking the YAML+Ruby typing
mechanism, so this is a perfect time for this. Right on.

Good, I have some other random thoughts below. Thanks for replying…

In the case of the above constructor, it would be impossible for YAML to
know in what order to pass the three parameters and I don’t have any
ideas for making the YAML loader work with the constructor.

Right, I was thinking of some heavyweight solution in which we passed
symbols to a YAML.construct or some such. Silliness basically.

I think the best solution for this would be akin to
Object#initialize_copy. In fact, it seems like YAML could call
Object#initialize_copy with the new object, should an
Object#initialize_copy method exist. Yeh?

Very good idea, yes. I see no drawbacks there so far.

Wish I had thought of that. I made do with a #defaults method that did
an ||= on each nil value. Cleaned up #initialize a bit, which now calls
it.

I was seriously thinking of an RCR to allow things like:

def initialize(@alpha,@beta,@gamma=5)
# Nothing else needed here
end

But I think Matz rejected a similar idea 2-3 years ago.

Yes, you can also do this with a typing callback:

[snip]

Ah, cool, yes.

Other questions…

  1. Have you given any thought to preserving comments in yaml files?
    E.g., I read in an entire file, modify some stuff, and write it out
    again – any practical way to keep the comments?

  2. I wish for a little more control over formatting. Possible?
    a. Specify order of fields instead of alphabetic
    b. Align field names and data in a “prettyprinted” way

Thanks for all your hard work…

Hal

“why the lucky stiff” ruby-talk@whytheluckystiff.net schrieb im
Newsbeitrag news:4067F665.1030500@whytheluckystiff.net

Good discussion, Hal. I’ve been really rethinking the YAML+Ruby typing
mechanism, so this is a perfect time for this. Right on.

Hal Fulton wrote:

When entities have default values in the constructor, we can omit them
when calling #new.

I’d like to be able to omit these in YAML also. (I can omit them now,
of course, but they get nil values).

So, if I understand you correctly, you use default values in the
constructor to enforce default values for object properties. In the
case below:

require “yaml”

class MyClass
def initialize(a,b,c=5)
@alpha, @beta, @gamma = a,b,c
end
end

…the use of c=5 is a way of ensuring that 5 is the default value for
@gamma.

A part of me wishes that YAML could somehow be smart enough to call
the constructor, maybe with a special call like ‘construct’ instead
of ‘load’ – but there are likely ramifications I haven’t thought of.

In the case of the above constructor, it would be impossible for YAML to
know in what order to pass the three parameters and I don’t have any
ideas for making the YAML loader work with the constructor.

I think the best solution for this would be akin to
Object#initialize_copy. In fact, it seems like YAML could call
Object#initialize_copy with the new object, should an
Object#initialize_copy method exist. Yeh?

Yes, you can also do this with a typing callback:

YAML::add_domain_type( “hypermetrics.com,2004”, “MyClass” ) do
>type, val|
val[‘gamma’] ||= 5
YAML::object_maker( MyClass, val )
end

YAML::load( <<EOY )
— !hypermetrics.com,2004/MyClass
alpha: 10
beta: 20
EOY
#=> #<MyClass:0x82418c0 @alpha=10, @gamma=5, @beta=30>

As food for thought: This could be extended into something more general:

class MyClass
DEFAULTS = {:gamma => 5}

def initialize(a,b,c=DEFAULTS[:gamma])
@alpha, @beta, @gamma = a,b,c
end
end

YAML::add_domain_type( “hypermetrics.com,2004”, “MyClass” ) do

type, val|

scheme, domain, name = type.split(/:/)
t = Object.const_get name

if t.const_defined? :DEFAULTS
t::DEFAULTS.each do |sym, v|
val[sym.to_s] ||= v
end
end

YAML::object_maker( t, val )
end

YAML::load( <<EOY )
— !hypermetrics.com,2004/MyClass
alpha: 10
beta: 20
EOY

robert

I was seriously thinking of an RCR to allow things like:

def initialize(@alpha,@beta,@gamma=5)
# Nothing else needed here
end

yes! and
def initialize(ref1, ref2,$global)
#stuff can only handle ref2,ref2, and $global
#evrything else raise an exception. that is true DBC :slight_smile:
end

But I think Matz rejected a similar idea 2-3 years ago.

doh!

Ps
sorry, I need more sleep and I’m getting mad

···

il Mon, 29 Mar 2004 20:30:57 +0900, Hal Fulton hal9000@hypermetrics.com ha scritto::

Hal Fulton wrote:

Other questions…

  1. Have you given any thought to preserving comments in yaml files?
    E.g., I read in an entire file, modify some stuff, and write it out
    again – any practical way to keep the comments?

Okay, yeah. It’s one of those things I’d like to have, but there hasn’t
been a big demand for it. Truly: I’m not too excited about coding it
in. But I could really use it as well.

  1. I wish for a little more control over formatting. Possible?
    a. Specify order of fields instead of alphabetic
    b. Align field names and data in a “prettyprinted” way

Specifying field order is a cinch.

class MyClass
def to_yaml_properties
[‘@gamma’, ‘@beta’, ‘@alpha’]
end
end

See the ‘Type Families’[1] section in the docs for the low down on
customizing loading and emitting further.

As for 2b, give me another day and I’ll 'splain about how to lay things
out with perfect daintiness. Just takes a minute to detail.

_why

[1] http://yaml4r.sourceforge.net/doc/page/type_families.htm

why the lucky stiff wrote:

  1. Have you given any thought to preserving comments in yaml files?
    E.g., I read in an entire file, modify some stuff, and write it out
    again – any practical way to keep the comments?

Okay, yeah. It’s one of those things I’d like to have, but there hasn’t
been a big demand for it. Truly: I’m not too excited about coding it
in. But I could really use it as well.

I understand about not looking forward to coding it.

I’ve been trying to figure out ways to approach it, and I fear it might
not be practical at all in the general case.

I considered a scheme where I did a to_yaml twice, storing the yaml in
a string. This seemed fruitless.

I thought of a template kind of thing, where objects would simply have
their yaml stuck into the text. This also hurts my head.

Then I started thinking of the potential difficulties. Suppose you
load 100 objects, and then dump 101. That seems doable; you just stick
the last one on the end.

But what if you try to put a new object in the middle? How do you
associate comments with yaml lines so that they can be kept together
correctly? How does it even ‘know’ that a particular object goes with
a particular chunk of text?

Here’s a thought. What if you attached singleton methods to each object
that had comments, like #pre_yaml and #post_yaml? These would return
the comment block before and after (whatever that means) the yaml code.
There could also be a hash or something that associated data item names
with their trailing comments.

But this is sheer speculation.

Cheers,
Hal

Hal Fulton wrote:

Other questions…

  1. Have you given any thought to preserving comments in yaml files?
    E.g., I read in an entire file, modify some stuff, and write it out
    again – any practical way to keep the comments?

Okay, yeah. It’s one of those things I’d like to have, but there hasn’t
been a big demand for it. Truly: I’m not too excited about coding it
in. But I could really use it as well.

Let me add my name to the list of people interrested in this feature.
OTOH, I do understand your lack of excitment to tackle it.

Guillaume.

···

On Mon, 2004-03-29 at 11:29, why the lucky stiff wrote:

  1. I wish for a little more control over formatting. Possible?
    a. Specify order of fields instead of alphabetic
    b. Align field names and data in a “prettyprinted” way

Specifying field order is a cinch.

class MyClass
def to_yaml_properties
[‘@gamma’, ‘@beta’, ‘@alpha’]
end
end

See the ‘Type Families’[1] section in the docs for the low down on
customizing loading and emitting further.

As for 2b, give me another day and I’ll 'splain about how to lay things
out with perfect daintiness. Just takes a minute to detail.

_why

[1] http://yaml4r.sourceforge.net/doc/page/type_families.htm

I like this - it’s elegant. Strings would probably be better than
singleton methods, though - easier to manipulate from within the code.

martin

···

Hal Fulton hal9000@hypermetrics.com wrote:

Here’s a thought. What if you attached singleton methods to each object
that had comments, like #pre_yaml and #post_yaml? These would return
the comment block before and after (whatever that means) the yaml code.