OpenStruct#update?

How 'bout an OpenStruct#update for adding values after initialization. Or is
there another way to do?

Thanks,
T.

Hi --

···

On Mon, 15 Nov 2004, trans. (T. Onoma) wrote:

How 'bout an OpenStruct#update for adding values after initialization. Or is
there another way to do?

OpenStruct needs to be very conservative about what methods it has,
since the whole point of it is to allow you to make up arbitrarily
named members.

But I'm also not sure what you need to do that you can't do. The
OpenStruct object should let you add values indefinitely.

David

--
David A. Black
dblack@wobblini.net

Hmm.. I also just had another related thought. I might also be useful if a
normal object could be "OpenStruct'd". I have a need for it at the moment.
Currently I take an object in as input and then dynamically define instance
vars with accessors on it as required, but often no initial object is given
in which case an OpenStruct is much easier to use. I'd rather just have the
OpenStruct capability from the get go.

T.

···

On Sunday 14 November 2004 03:42 pm, trans. (T. Onoma) wrote:

How 'bout an OpenStruct#update for adding values after initialization. Or
is there another way to do?

Hi David,

> How 'bout an OpenStruct#update for adding values after initialization. Or
> is there another way to do?

OpenStruct needs to be very conservative about what methods it has,
since the whole point of it is to allow you to make up arbitrarily
named members.

Why so conservative? So they don't overwrite standard object methods? I
wondered why accessors weren't used. I suppose a hash is faster too. Hek,
maybe '@' itself should be hash and forget about it :wink:

But I'm also not sure what you need to do that you can't do. The
OpenStruct object should let you add values indefinitely.

This is what I mean:

  o = OpenStruct.new( foo_hash )
  
  # later ...

  o.update( bar_hash )

The reason is because I am modifying and using the object on the fly.

Thanks,
T.

···

On Sunday 14 November 2004 03:51 pm, David A. Black wrote:

On Mon, 15 Nov 2004, trans. (T. Onoma) wrote:

Hi,

It's amazing that OpenStruct which is a proof of concept tiny toy
attracts so many users.

···

In message "Re: OpenStruct#update ?" on Mon, 15 Nov 2004 06:07:11 +0900, "trans. (T. Onoma)" <transami@runbox.com> writes:

Hmm.. I also just had another related thought. I might also be useful if a
normal object could be "OpenStruct'd". I have a need for it at the moment.
Currently I take an object in as input and then dynamically define instance
vars with accessors on it as required, but often no initial object is given
in which case an OpenStruct is much easier to use. I'd rather just have the
OpenStruct capability from the get go.

Can you be more specific, preferably with code example?

              matz.

Hi --

Hi David,

> > How 'bout an OpenStruct#update for adding values after initialization. Or
> > is there another way to do?
>
> OpenStruct needs to be very conservative about what methods it has,
> since the whole point of it is to allow you to make up arbitrarily
> named members.

Why so conservative? So they don't overwrite standard object methods? I
wondered why accessors weren't used. I suppose a hash is faster too. Hek,
maybe '@' itself should be hash and forget about it :wink:

I'm assuming so. Actually here's what happens if you try:

  irb(main):020:0> o = OpenStruct.new
  => <OpenStruct>
  irb(main):021:0> o.class = 1
  => 1
  irb(main):022:0> o.class
  => OpenStruct

> But I'm also not sure what you need to do that you can't do. The
> OpenStruct object should let you add values indefinitely.

This is what I mean:

  o = OpenStruct.new( foo_hash )
  
  # later ...

  o.update( bar_hash )

The reason is because I am modifying and using the object on the fly.

It's easy to write:

  o = OpenStruct.new({ :a => 1 })
  def o.update(h); h.each {|k,v| send("#{k}=",v)}; end
  o.update({ :a => 2})
  p o.a

  # => 2

(Modularize and error-check as required :slight_smile:

David

···

On Mon, 15 Nov 2004, trans. (T. Onoma) wrote:

On Sunday 14 November 2004 03:51 pm, David A. Black wrote:
> On Mon, 15 Nov 2004, trans. (T. Onoma) wrote:

--
David A. Black
dblack@wobblini.net

Hi,

It's amazing that OpenStruct which is a proof of concept tiny toy
attracts so many users.

It is a very convienet way to access data that is object polymorphic.

Problem, of course, is namespace clash with core methods. What might help: 1)
a "kernelless" object class which reduces the core methods to bare minimum.
2) Have specialized core aliases like __id__ and __send__ (e.g. __class__)
for all methods considered core. These *cannot* be overridden ever. And 3)
have private and public methods have separate namespaces --could that help?
Might that even boost method lookup speeds? Just some thoughts on the matter.

On the whole I'd rather be able to override methods.

>Hmm.. I also just had another related thought. I might also be useful if a
>normal object could be "OpenStruct'd". I have a need for it at the moment.
>Currently I take an object in as input and then dynamically define
> instance vars with accessors on it as required, but often no initial
> object is given in which case an OpenStruct is much easier to use. I'd
> rather just have the OpenStruct capability from the get go.

Can you be more specific, preferably with code example?

Sure. Okay first, basically what I was doing, given object o and data in hash
h:

    h.each do |k,v|
      o.instance_variable_set("@#{k}", v)
      o.instance_eval <<-EOS
        def #{k}; @#{k}; end
        def #{k}=(x); @#{k}=x; end
      EOS
    end

Now if o is an OpenStruct, the above is much easier, well, easier after I've
added the before mentioned #update method:

  o.update( h )

But o might not be an OpenStruct --the library user may have a pre-made object
that they want to use. What might be of use then, rather then a stand alone
OpenStruct object is a way to "open" a regular object:

  o.extend OpenStruct

Actually, if one could extend using a class, instead of just a module, I think
it might almost work just like that.

Thanks,
T.

···

On Sunday 14 November 2004 06:16 pm, Yukihiro Matsumoto wrote:

In message "Re: OpenStruct#update ?" > > on Mon, 15 Nov 2004 06:07:11 +0900, "trans. (T. Onoma)" <transami@runbox.com> writes:

Ah, what the hek! I pulled down 1.9 and modified. Below you will find code.
Let me know if you'd like me to send code as attachment via private mail.

Okay so the trick was simply to move everything into a mixin module (expect
the initialize method). I also changed @table to @__table__ to help prevent
possible name clash. The only other changed required was using

  @__table__ ||= {}

in a number of places (too bad no better way to do that). Finally I just
called the module OpenStructable --seems like a good a name as any.

Also, I found what looks to be a bug in current 1.9 version. The initialize
method wasn't calling the newly added #new_ostruct_member method. I fixed and
added #update method. Also, is #new_ostruct_member supposed to be private?
Currently it is public. If it remains public, I recommend a more generic
name. Not sure what though.

Hope you like,
T.

···

On Sunday 14 November 2004 06:16 pm, Yukihiro Matsumoto wrote:

Can you be more specific, preferably with code example?

       matz.

------------

#
# = ostruct.rb: OpenStruct implementation
#
# Author:: Yukihiro Matsumoto & Thomas Sawyer
# Documentation:: Gavin Sinclair
#
# OpenStruct allows the creation of data objects with arbitrary attributes.
# See OpenStruct for an example. OpenStruct is implemented with a resuable
# mixin module OpenStructable.
#

# OpensStructable is a mixin module which can provide OpenStruct behavior to
# any class or object.
#
# require 'ostruct'
#
# record = Object.new
# record.extend OpenStructable
#
# record.name = "John Smith"
# record.age = 70
# record.pension = 300
#
# puts record.name # -> "John Smith"
# puts record.address # -> nil
#
module OpenStructable

  # Duplicate an OpenStruct object members.
  def initialize_copy(orig)
    super
    @__table__ = @__table__.dup
  end

  def new_ostruct_member(name)
    self.instance_eval %{
      def #{name}; @__table__[:#{name}]; end
      def #{name}=(x); @__table__[:#{name}] = x; end
    }
  end

  #
  # Generate additional attributes and values.
  #
  def update(hash)
    @__table__ ||= {}
    if hash
      for k,v in hash
        @__table__[k.to_sym] = v
        new_ostruct_member(k)
      end
    end
  end
  
  def method_missing(mid, *args) # :nodoc:
    mname = mid.id2name
    len = args.length
    if mname =~ /=$/
      if len != 1
        raise ArgumentError, "wrong number of arguments (#{len} for 1)",
caller(1)
      end
      if self.frozen?
        raise TypeError, "can't modify frozen #{self.class}", caller(1)
      end
      mname.chop!
      @__table__ ||= {}
      @__table__[mname.intern] = args[0]
      self.new_ostruct_member(mname)
    elsif len == 0
      @__table__ ||= {}
      @__table__[mid]
    else
      raise NoMethodError, "undefined method `#{mname}' for #{self}",
caller(1)
    end
  end

  #
  # Remove the named field from the object.
  #
  def delete_field(name)
    @__table__ ||= {}
    @__table__.delete name.to_sym
  end

  #
  # Returns a string containing a detailed summary of the keys and values.
  #
  def inspect
    str = "<#{self.class}"
    for k,v in (@__table__ ||= {})
      str << " #{k}=#{v.inspect}"
    end
    str << ">"
  end

  def __table__ # :nodoc:
    @__table__ ||= {}
  end
  protected :__table__

  #
  # Compare this object and +other+ for equality.
  #
  def ==(other)
    return false unless(other.kind_of?(OpenStruct))
    return @__table__ == other.table
  end
end

#
# OpenStruct allows you to create data objects and set arbitrary attributes.
# For example:
#
# require 'ostruct'
#
# record = OpenStruct.new
# record.name = "John Smith"
# record.age = 70
# record.pension = 300
#
# puts record.name # -> "John Smith"
# puts record.address # -> nil
#
# It is like a hash with a different way to access the data. In fact, it is
# implemented with a hash, and you can initialize it with one.
#
# hash = { "country" => "Australia", :population => 20_000_000 }
# data = OpenStruct.new(hash)
#
# p data # -> <OpenStruct country="Australia" population=20000000>
#
class OpenStruct
  include OpenStructable
  
  #
  # Create a new OpenStruct object. The optional +hash+, if given, will
  # generate attributes and values. For example.
  #
  # require 'ostruct'
  # hash = { "country" => "Australia", :population => 20_000_000 }
  # data = OpenStruct.new(hash)
  #
  # p data # -> <OpenStruct country="Australia" population=20000000>
  #
  # By default, the resulting OpenStruct object will have no attributes.
  #
  def initialize(hash=nil)
    update(hash)
  end
end

Yes, no, maybe?

Can you be more specific, preferably with code example?

       matz.

Ah, what the hek! I pulled down 1.9 and modified. Below you will find code.
Let me know if you'd like me to send code as attachment via private mail.

Okay so the trick was simply to move everything into a mixin module (expect
the initialize method). I also changed @table to @__table__ to help prevent
possible name clash. The only other changed required was using

  @__table__ ||= {}

in a number of places (too bad no better way to do that). Finally I just
called the module OpenStructable --seems like a good a name as any.

Also, I found what looks to be a bug in current 1.9 version. The initialize
method wasn't calling the newly added #new_ostruct_member method. I fixed and
added #update method. Also, is #new_ostruct_member supposed to be private?
Currently it is public. If it remains public, I recommend a more generic
name. Not sure what though.

Hope you like,
T.

···

--- Original Message ---
On Sunday 14 November 2004 06:16 pm, Yukihiro Matsumoto wrote:

------------

#
# = ostruct.rb: OpenStruct implementation
#
# Author:: Yukihiro Matsumoto
# Contributor:: Thomas Sawyer
# Documentation:: Gavin Sinclair
#
# OpenStruct allows the creation of data objects with arbitrary attributes.
# See OpenStruct for an example. OpenStruct is implemented with a resuable
# mixin module OpenStructable.
#

# OpensStructable is a mixin module which can provide OpenStruct behavior to
# any class or object.
#
# require 'ostruct'
#
# record = Object.new
# record.extend OpenStructable
#
# record.name = "John Smith"
# record.age = 70
# record.pension = 300
#
# puts record.name # -> "John Smith"
# puts record.address # -> nil
#
module OpenStructable

  # Duplicate an OpenStruct object members.
  def initialize_copy(orig)
    super
    @__table__ = @__table__.dup
  end

  def new_ostruct_member(name)
    self.instance_eval %{
      def #{name}; @__table__[:#{name}]; end
      def #{name}=(x); @__table__[:#{name}] = x; end
    }
  end

  #
  # Generate additional attributes and values.
  #
  def update(hash)
    @__table__ ||= {}
    if hash
      for k,v in hash
        @__table__[k.to_sym] = v
        new_ostruct_member(k)
      end
    end
  end
  
  def method_missing(mid, *args) # :nodoc:
    mname = mid.id2name
    len = args.length
    if mname =~ /=$/
      if len != 1
        raise ArgumentError, "wrong number of arguments (#{len} for 1)",
caller(1)
      end
      if self.frozen?
        raise TypeError, "can't modify frozen #{self.class}", caller(1)
      end
      mname.chop!
      @__table__ ||= {}
      @__table__[mname.intern] = args[0]
      self.new_ostruct_member(mname)
    elsif len == 0
      @__table__ ||= {}
      @__table__[mid]
    else
      raise NoMethodError, "undefined method `#{mname}' for #{self}",
caller(1)
    end
  end

  #
  # Remove the named field from the object.
  #
  def delete_field(name)
    @__table__ ||= {}
    @__table__.delete name.to_sym
  end

  #
  # Returns a string containing a detailed summary of the keys and values.
  #
  def inspect
    str = "<#{self.class}"
    for k,v in (@__table__ ||= {})
      str << " #{k}=#{v.inspect}"
    end
    str << ">"
  end

  def __table__ # :nodoc:
    @__table__ ||= {}
  end
  protected :__table__

  #
  # Compare this object and +other+ for equality.
  #
  def ==(other)
    return false unless(other.kind_of?(OpenStruct))
    return @__table__ == other.table
  end
end

#
# OpenStruct allows you to create data objects and set arbitrary attributes.
# For example:
#
# require 'ostruct'
#
# record = OpenStruct.new
# record.name = "John Smith"
# record.age = 70
# record.pension = 300
#
# puts record.name # -> "John Smith"
# puts record.address # -> nil
#
# It is like a hash with a different way to access the data. In fact, it is
# implemented with a hash, and you can initialize it with one.
#
# hash = { "country" => "Australia", :population => 20_000_000 }
# data = OpenStruct.new(hash)
#
# p data # -> <OpenStruct country="Australia" population=20000000>
#
class OpenStruct
  include OpenStructable
  
  #
  # Create a new OpenStruct object. The optional +hash+, if given, will
  # generate attributes and values. For example.
  #
  # require 'ostruct'
  # hash = { "country" => "Australia", :population => 20_000_000 }
  # data = OpenStruct.new(hash)
  #
  # p data # -> <OpenStruct country="Australia" population=20000000>
  #
  # By default, the resulting OpenStruct object will have no attributes.
  #
  def initialize(hash=nil)
    update(hash)
  end
end

Ouch. I think that may be a bit too conservative. It's better that someone can
shoot themselves in the foot rather than having someone else do it for them.
I just got stung with:

  require 'yaml'

  q = YAML.load %Q{

···

On Sunday 14 November 2004 04:27 pm, David A. Black wrote:

> Why so conservative? So they don't overwrite standard object methods? I
> wondered why accessors weren't used. I suppose a hash is faster too. Hek,
> maybe '@' itself should be hash and forget about it :wink:

I'm assuming so. Actually here's what happens if you try:

  irb(main):020:0> o = OpenStruct.new
  => <OpenStruct>
  irb(main):021:0> o.class = 1
  => 1
  irb(main):022:0> o.class
  => OpenStruct

  ---
  x: 10
  y: 20
  ...
  }

  o = OpenStruct.new( q )

  o.instance_eval { x } #=> 10
  o.instance_eval { y } #=> nil

> > But I'm also not sure what you need to do that you can't do. The
> > OpenStruct object should let you add values indefinitely.
>
> This is what I mean:
>
> o = OpenStruct.new( foo_hash )
>
> # later ...
>
> o.update( bar_hash )
>
> The reason is because I am modifying and using the object on the fly.

It's easy to write:

  o = OpenStruct.new({ :a => 1 })
  def o.update(h); h.each {|k,v| send("#{k}=",v)}; end
  o.update({ :a => 2})
  p o.a

  # => 2

Cool. although I prefer to build it in. I looked at the ostruct.rb code. Very
simple. All the "safety" logic is in #method_missing, so this is fine:

require 'ostruct'
class OpenStruct
  # Insert/update hash data on the fly.
  def update( hash )
    if hash
      for k,v in hash
        @table[k.to_sym] = v
      end
    end
  end
end

Seems a reasonable addition to standard lib, yes?

Thanks,
T.

Hi,

···

In message "Re: OpenStruct#update ?" on Mon, 15 Nov 2004 06:27:51 +0900, "David A. Black" <dblack@wobblini.net> writes:

I'm assuming so. Actually here's what happens if you try:

irb(main):020:0> o = OpenStruct.new
=> <OpenStruct>
irb(main):021:0> o.class = 1
=> 1
irb(main):022:0> o.class
=> OpenStruct

I'm thinking of making OpenStruct raise error for assignment to
existing method. I'm not sure whether I should prohibit private
method overriding, i.e. cases Hal pointed out in [ruby-talk:117889].

              matz.

trans. (T. Onoma) wrote:

Sure. Okay first, basically what I was doing, given object o and data in hash h:

    h.each do |k,v|
      o.instance_variable_set("@#{k}", v)
      o.instance_eval <<-EOS
        def #{k}; @#{k}; end def #{k}=(x); @#{k}=x; end
      EOS
    end

h.each do |k,v|
   class << o; self; end.send(:attr_accessor, k)
   o.k = v
end

Maybe .meta_class and .meta_class_eval should really be part of Standard Ruby...

[...]

While you are at it, please consider

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/3687

and the other msgs in that thread.

···

On Wed, Nov 17, 2004 at 08:53:11PM +0900, trans. (T. Onoma) wrote:

Yes, no, maybe?

--- Original Message ---

On Sunday 14 November 2004 06:16 pm, Yukihiro Matsumoto wrote:
> Can you be more specific, preferably with code example?
>
> matz.

Ah, what the hek! I pulled down 1.9 and modified. Below you will find code.
Let me know if you'd like me to send code as attachment via private mail.

--
Hassle-free packages for Ruby?
RPA is available from http://www.rubyarchive.org/

Hi --

Hi,

>I'm assuming so. Actually here's what happens if you try:
>
> irb(main):020:0> o = OpenStruct.new
> => <OpenStruct>
> irb(main):021:0> o.class = 1
> => 1
> irb(main):022:0> o.class
> => OpenStruct

I'm thinking of making OpenStruct raise error for assignment to
existing method. I'm not sure whether I should prohibit private
method overriding, i.e. cases Hal pointed out in [ruby-talk:117889].

What about =-methods?

  require 'ostruct'
  
  def x=(y)
    puts "In x=()"
  end
  
  self.x = 1 # In x=()
  
  o = OpenStruct.new
  o.x = 1 # Should this print "In x=()" ?

Probably a marginal case :slight_smile:

David

···

On Mon, 15 Nov 2004, Yukihiro Matsumoto wrote:

In message "Re: OpenStruct#update ?" > on Mon, 15 Nov 2004 06:27:51 +0900, "David A. Black" <dblack@wobblini.net> writes:

--
David A. Black
dblack@wobblini.net

trans. (T. Onoma) wrote:
> Sure. Okay first, basically what I was doing, given object o and data in
> hash h:
>
> h.each do |k,v|
> o.instance_variable_set("@#{k}", v)
> o.instance_eval <<-EOS
> def #{k}; @#{k}; end
> def #{k}=(x); @#{k}=x; end
> EOS
> end

h.each do |k,v|
   class << o; self; end.send(:attr_accessor, k)
   o.k = v
end

Nice. I still perfer to use instance_variable_set, but the send :attr_accessor
is a nice improvement. Thanks.

Maybe .meta_class and .meta_class_eval should really be part of Standard
Ruby...

I have them in my own lib as #virtual_class. So I could use that as well.
Speaking of which...

Matz, can we get the official word on what the name for these is going to be?
Is it meta class, singleton class, virtual class or ... ? (personally I like
instance class). I would like my lib to be able to conform to the "standard".

Thanks,
T.

···

On Monday 15 November 2004 06:48 am, Florian Gross wrote:

"Florian Gross" <flgr@ccan.de> schrieb im Newsbeitrag
news:2vrj8eF2oj365U1@uni-berlin.de...

trans. (T. Onoma) wrote:

> Sure. Okay first, basically what I was doing, given object o and data

in hash

> h:
>
> h.each do |k,v|
> o.instance_variable_set("@#{k}", v)
> o.instance_eval <<-EOS
> def #{k}; @#{k}; end
> def #{k}=(x); @#{k}=x; end
> EOS
> end

h.each do |k,v|
   class << o; self; end.send(:attr_accessor, k)
   o.k = v
end

Are you sure, this works? IMHO this is more efficient:

class << o; self; end.send(:attr_accessor, *h.keys)
h.each do |k,v|
   o.send("#{k}=", v)
end

But it would be even better to check for existing methods in order to not
overwrite existing methods:

cl = class << o; self; end
im = cl.instance_methods
h.each do |k,v|
   cl.send(:attr_reader, k) unless im.include?(k.to_s)
   cl.send(:attr_writer, k) unless im.include?("#{k}=")
   o.send("#{k}=", v)
end

Kind regards

    robert

Hi --

trans. (T. Onoma) wrote:

> Sure. Okay first, basically what I was doing, given object o and data in hash
> h:
>
> h.each do |k,v|
> o.instance_variable_set("@#{k}", v)
> o.instance_eval <<-EOS
> def #{k}; @#{k}; end
> def #{k}=(x); @#{k}=x; end
> EOS
> end

h.each do |k,v|
   class << o; self; end.send(:attr_accessor, k)
   o.k = v
end

Maybe .meta_class and .meta_class_eval should really be part of Standard
Ruby...

I've got an RCR in for singleton_class. (I know, the terminology is
different, but it's the same idea :slight_smile: I still don't know what the
perfect word would be for That Class.) I don't think a separate
_class_eval method would be necessary or good. As with every other
class, you could just call class_eval on the class object.

I firmly believe that having a singleton_class method (or whatever
it's called) would make it much, much easier for people to understand
the whole design. See <http://www.rcrchive.net/rcr/show/231&gt;\.

David

···

On Mon, 15 Nov 2004, Florian Gross wrote:

--
David A. Black
dblack@wobblini.net

Okay, thanks. So what constitutes compatible marshal data?

T.

···

On Wednesday 17 November 2004 07:04 am, Mauricio Fernández wrote:

While you are at it, please consider

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/3687

and the other msgs in that thread.

Robert Klemme wrote:

"Florian Gross" <flgr@ccan.de> schrieb im Newsbeitrag

h.each do |k,v|
  class << o; self; end.send(:attr_accessor, k)
  o.k = v
end

Are you sure, this works? IMHO this is more efficient:

class << o; self; end.send(:attr_accessor, *h.keys)
h.each do |k,v|
   o.send("#{k}=", v)
end

You are right of course. I also like how you moved the attr_accessor out of the loop -- nice idea.

But it would be even better to check for existing methods in order to not
overwrite existing methods:

cl = class << o; self; end
im = cl.instance_methods
h.each do |k,v|
   cl.send(:attr_reader, k) unless im.include?(k.to_s)
   cl.send(:attr_writer, k) unless im.include?("#{k}=")
   o.send("#{k}=", v)
end

Hm, I think that would still overwrite methods of o's class and inherited ones.

What about this?

accessors = h.keys - o.methods
class << o; self; end.send(:attr_accessor, *accessors)
h.each do |key, value|
   o.send("#{key}=", value) if accessors.include?(key)
end

David A. Black wrote:

Maybe .meta_class and .meta_class_eval should really be part of Standard Ruby...

I've got an RCR in for singleton_class. (I know, the terminology is
different, but it's the same idea :slight_smile: I still don't know what the
perfect word would be for That Class.) I don't think a separate
_class_eval method would be necessary or good. As with every other
class, you could just call class_eval on the class object.

I firmly believe that having a singleton_class method (or whatever
it's called) would make it much, much easier for people to understand
the whole design. See <http://www.rcrchive.net/rcr/show/231&gt;\.

Hm, looks like I already voted on it. I can live with it being named #singleton_class, #meta_class or even #virtual_class -- I don't really know what name would be best. I'm just in favor of #meta_class because it avoids the name clash with the singleton pattern. (Which seems to be obsolete in Ruby anyway -- it seems to be the case that everywhere where you would use it you can just as well use a Module...)

I guess it's probably best to let matz decide the name.