e.g. a class which represents the an object id, the object id have to be
a string , because it's stored in database.
It has to be convertable to a string, but that does not mean OID *isA*
String.
So to get a part of the id,
you define an accessor, which scans the string.
.... and by using String methods I can easily break the OID:
class OID < String
RX = /^(\d+)-(\d+)$/
def initialize(str)
raise ArgumentError unless RX =~ str
super
end
def major; RX =~ self; $1; end
def minor; RX =~ self; $2; end
end
oid = OID.new("123456") # wrong format => error, ok!
oid = OID.new("123-456")
oid.gsub!(/.*/, 'X')
oid.major # oops!
I'd say an OID is not a string. It has a String representation, but it is
conceptually something completely different. Especially if your OIDs must
conform to a certain format as shown above. Also, you might want to
change the internal representation if that is more appropriate at some
point in time (e.g. because performance of #major and #minor is too bad).
But from a practical view, I'd rather go with some module_functions,
because the conversions all over the code like String#to_oid are too messy.
Yes, but when it comes to binary representation, I have to call everywhere
to_s, also not beatyful.
The term namespace is possibly wrong, but my idea is:
namespace MyNames
class String # makes a copy of String class
end
s = "xxx" # constructor of MyNames::String is called
end
Same thing for every string creation.
But that would require a lot of change in the interpreter,
every rb_str_new() must know the current namespace.
That's not how namespaces work (at least in C++). First, class String in
MyNames is a totally new String class that has nothing to do with any
other class with the same name unless you inherit that class. Second,
"xxx" is a literal that is bound to the standard type String (char* in
C/C++), similarly as 1.234 is bound to represent a float. You don't
change that by introducing namespaces. Third, places in code that create
strings one way or the other will always create standard strings. If the
declaration of a new class with the same name as another class in a
different namespace had the side effect that *all* places in code now use
the new class, type safety would be completely down the drain - apart from
all other sorts of problems (how should a compiler handle this in C++?).
What you'd rather want is a mechanism that replaces the binding of certain
literals to types ("xxx" => String, 1.234 => float etc.). But then, in
Ruby it's far easier to simply extend String. Still I think in most cases
it is not a good idea to use a sub class of String as an application
class, since that brings all sorts of problems with it.
Recently I attended a lecture of the creator(Erik Ernst) of the
language gbeta, which solves this problem nicely, but
from a very different approach.
How do they do it there?
robert