Variable names

  • Thread starter David King Landrith
  • Start date
D

David King Landrith

About a year ago, I wrote a simple type enforcement library that adds a
should_be method to the Object class. This method looks like this:

def should_be(types, varName)
# types is either a Class or an array of Classes
# that are legal types (or super-types, if you will)
# for self

# varName is the symbol for the variable; we use this
# when we throw the exception

<type checking code>

# we throw an exception if self is not of one of
# the types specified
end

So, say we have a method print_line that takes two parameters (1) an
integer line number and (2) a string which is the line.

def print_line(lineNo, line)
lineNo.should_be(Integer, :lineNo)
line.should_be(String, :line)
# by now, we would have thrown a TypeError if lineNo
# and line are not an Integer and a String respectively

<code to make this method live up to its name>

end

We've been using this for a year now. Several months ago I rewrote it
so that it is in C so that it doesn't appreciably increase overhead.
The good news is that it works quite well and completely fulfills our
type checking needs.

The issue is that I don't like having to pass the symbol for the
variable, because it strikes me as inelegant. Right now, I only pass
the symbol so that I can construct an error message saying (for
example) "variable 'loginIDs' is of the wrong type 'Integer'; expected
'Array'". I feel that it would be much cleaner to simply say
loginIDs.should_be(Integer). I may be quite dense and perhaps I am
missing something obvious, but I have combed through the source code
for 1.6.x and 1.8.1 and I haven't been able to find anything (I've
tried every conceivable combination of 'object id' and 'name for id'
functions, but of course these are two entirely different kinds of
ids).

Thus my question:

Is there any way to access the name of a given variable instance from
within it? In other words, for any object x, is there C function to
which I can pass self to determine that the program calls it 'x'?

Thanks,

Dave


-------------------------------------------------------
David King Landrith
(w) 617.227.4469x213
(h) 617.696.7133

Life is tough. It's even tougher if you're
an idiot. --John Wayne
 
D

Dave Thomas

Is there any way to access the name of a given variable instance from
within it? In other words, for any object x, is there C function to
which I can pass self to determine that the program calls it 'x'?

You have the file name and line number, and you may even have the file
itself in SCRIPT_LINES, so you could cheat and find the name from that.

I'm interested in tis experiment: how often does it catch a problem
that you didn't catch though unit testing? Putting that another way:
how often do you see these type errors in testing, and how often in
production?


Cheers

Dave
 
T

ts

D> Is there any way to access the name of a given variable instance from
D> within it? In other words, for any object x, is there C function to
D> which I can pass self to determine that the program calls it 'x'?

Well, with this

a = b = 12

which is the name associated with the object 12 ?


Guy Decoux
 
D

David King Landrith

D> Is there any way to access the name of a given variable instance
from
D> within it? In other words, for any object x, is there C function to
D> which I can pass self to determine that the program calls it 'x'?

Well, with this

a = b = 12
which is the name associated with the object 12 ?

From what I understand, since 12 is a FixNum, a and b end up being
separate FixNum objects with their own separate values of 12. But this
strikes me as beside the point.

In the C api, each function gets passed a pointer to the struct which
represents self. You can pass this pointer to any number of functions
to get information about self; e.g., class along with variables and
their contents. So that for the FixNum 'a' above, we could discern
that it was a FixNum. The question is: Is there a method that wil tell
me that it is called 'a'. If 'self' end up being a literal, then I
suppose its name is its value, but it seems to me that this would
simply be a question of how the interpreter works vis a vis its symbols
table.

-------------------------------------------------------
David King Landrith
(w) 617.227.4469x213
(h) 617.696.7133

Life is tough. It's even tougher if you're
an idiot. --John Wayne
 
D

David King Landrith

You have the file name and line number, and you may even have the file
itself in SCRIPT_LINES, so you could cheat and find the name from
that.

I'm looking for something more general. We don't actually have such a
print_line method, I simply made it up for the email since it was a
good example.
I'm interested in tis experiment: how often does it catch a problem
that you didn't catch though unit testing? Putting that another way:
how often do you see these type errors in testing, and how often in
production?

Often enough to justify it, given the complexity of our application.
We've written a Ruby api upon which our program is based, and it has
about than 18,000 lines (25k ruby, 3k in C). Our program (or group of
programs surrounding the application) totals least 25,000 lines. As a
consequence, we have tons of unforeseen contingencies and type checking
provides an important way to eliminate one class of these.

Since most of our application touches a SQL database in some way (we've
rolled our own ruby database API in C to handle persistence layers and
eliminate the overhead endemic to the dbd/dbi arrangement, since our
tables have 10s of millions of records and we're pushing and pulling
gigabytes of data) destructive errors are a real possibility; E.g., we
don't want to insert #<Module::Object:0x40536218> into a varchar field.
And since we often have a method calling a method calling a method and
so on, without type checking it can be quite difficult to locate where
our string got swapped for something else. Also, given the complexity
of the program, the behavior that elicits the swap may very well be
latent in very, very well tested code. Does this make sense?

-------------------------------------------------------
David King Landrith
(w) 617.227.4469x213
(h) 617.696.7133

Life is tough. It's even tougher if you're
an idiot. --John Wayne
 
M

Mark Hubbart

From what I understand, since 12 is a FixNum, a and b end up being
separate FixNum objects with their own separate values of 12. But
this strikes me as beside the point.

I think this is what ts is pointing out:

# set a, b and c; set a's @foo instance variable to 42
a = b = 23 #=> 23
a.instance_eval{@foo=42} #=> 42
c = 23 #=> 23

# show everyone's @foo
[ a.instance_eval{@foo},
b.instance_eval{@foo},
c.instance_eval{@foo},
23.instance_eval{@foo}] #=> [42, 42, 42, 42]

# show everyone's id
[a.id, b.id, c.id, 23.id] #=> [47, 47, 47, 47]

All instances of 23 are exactly the same object. No difference
whatsoever. the variable name is like a nickname (thanks Why :), it's
just one of many pointers to the object. I really don't think that
there is any way to get the name assigned to that pointer, especially
since the number of names assigned to that one object can be anywhere
from 0 to infinity :) (well, infinite for practical purposes anyway...)

I looked around though, at Symbols.all_symbols,
ObjectSpace.each_object, and I couldn't find any way to tie them
together... perhaps there is a way, but I'm not sure that you will be
getting the right symbol for the context you are in even if you do...

--Mark
 
D

Dan Doel

From what I understand, since 12 is a FixNum, a and b end up being
separate FixNum objects with their own separate values of 12. But this
strikes me as beside the point.

This is incorrect. a and b would both point to the same FixNum object.
In fact, I wouldn't be surprised if all direct references to 12 were the same
FixNum object for efficiency purposes.
In the C api, each function gets passed a pointer to the struct which
represents self. You can pass this pointer to any number of functions
to get information about self; e.g., class along with variables and
their contents. So that for the FixNum 'a' above, we could discern
that it was a FixNum. The question is: Is there a method that wil tell
me that it is called 'a'. If 'self' end up being a literal, then I
suppose its name is its value, but it seems to me that this would
simply be a question of how the interpreter works vis a vis its symbols
table.

The name of the variable that points to the object isn't an inherent part
of the object, though. Like above, you can have any number of variables
representing the same object. Also, you could have many objects referencing
that same object (for example, if it's stored in an array). Should an object
also keep references to all objects that reference it?

Variable names are incidental. For example:

def foo
a = String.new
end

x = foo

When inside the method foo, the string is pointed to by the local variable a.
However, outside, it's pointed to by the local variable x. What has changed
about the object? Nothing.

Variables are a lot like pointers in C. You allocate a pointer to store the
address of some other memory. It doesn't make sense for every piece of
memory to also store the addresses of all pointers that point to it.

- Dan
 
M

Mauricio Fernández

You have the file name and line number, and you may even have the file
itself in SCRIPT_LINES, so you could cheat and find the name from that.

I'm interested in tis experiment: how often does it catch a problem
that you didn't catch though unit testing? Putting that another way:
how often do you see these type errors in testing, and how often in
production?

This looks like a restricted version of Eivind Eklund's types.rb. Here's
what the author had to say about it:

"The reason I didn't do any particularly public release of it was
that I found that adding type checks to ruby programs were worse
than useless for me - it got in the way of my refactoring, without
catching many bugs."

See http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/84841.

--
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

"You, sir, are nothing but a pathetically lame salesdroid!
I fart in your general direction!"
-- Randseed on #Linux
 
D

David King Landrith

The name of the variable that points to the object isn't an inherent
part
of the object, though. Like above, you can have any number of
variables
representing the same object. Also, you could have many objects
referencing
that same object (for example, if it's stored in an array). Should an
object
also keep references to all objects that reference it?

Variable names are incidental. For example:

def foo
a = String.new
end

x = foo

When inside the method foo, the string is pointed to by the local
variable a.
However, outside, it's pointed to by the local variable x. What has
changed
about the object? Nothing.

Variables are a lot like pointers in C. You allocate a pointer to
store the
address of some other memory. It doesn't make sense for every piece of
memory to also store the addresses of all pointers that point to it.

- Dan

Let me restate the question:

Whenever a method is called on an object, one and only one symbol is
used to represent the object. Is there any way to determine which
symbol was representing the object at the time that the method was
invoked?

Everything that has been said thus far leads me to believe that the
answer is no, but nobody has hit the point square on. I'm anxious to
clarify my question or provide more information if my question remains
unclear. But (as usual -- and this is the reason I rarely use this
list) people seem more interested in pedantry than genuine assistance.
Don't get me wrong, the answers are informative and often fill me with
awe at vast expanses of knowledge possessed by those that offer them.
They just provide both too much and not enough information at the same
time, which typically indicates that you're dealing with either an
obscurantist (e.g., a politician) or a pedant.


-------------------------------------------------------
David King Landrith
(w) 617.227.4469x213
(h) 617.696.7133

One useless man is a disgrace, two
are called a law firm, and three or more
become a congress -- John Adams
-------------------------------------------------------
public key available upon request


-------------------------------------------------------
David King Landrith
(w) 617.227.4469x213
(h) 617.696.7133

Life is tough. It's even tougher if you're
an idiot. --John Wayne
 
D

Dave Thomas

Let me restate the question:

Whenever a method is called on an object, one and only one symbol is
used to represent the object. Is there any way to determine which
symbol was representing the object at the time that the method was
invoked?

Not always:

(1 + 2).abs


Cheers

Dave
 
D

David King Landrith

Replies like this make this list next to useless.

Not always:

(1 + 2).abs


Cheers

Dave
-------------------------------------------------------
David King Landrith
(w) 617.227.4469x213
(h) 617.696.7133

Life is tough. It's even tougher if you're
an idiot. --John Wayne
 
G

Gennady

David King Landrith wrote:

Remarks like this make such persons unwelcome to this list.
Gennady.
 
S

Simon Strandgaard

On Sat, 03 Apr 2004 02:20:24 +0900, David King Landrith wrote:
[snip]
Is there any way to access the name of a given variable instance from
within it? In other words, for any object x, is there C function to
which I can pass self to determine that the program calls it 'x'?

Thanks,

You want something like this ?

server> ruby a.rb
a.rb:4:in `should_be': expected String, but got Fixnum (TypeError)
from a.rb:12:in `test'
from a.rb:16
server> expand -t2 a.rb
class Object
def should_be(klass)
unless self.kind_of?(klass)
raise TypeError, <<-MSG.gsub(/^\s*/, '')
expected #{klass}, but got #{self.class}
MSG
end
end
end
def test(str)
str.should_be(String)
end
test("hello")
test(666) # boom.. as we expect
server>
 
D

Dave Thomas

Replies like this make this list next to useless.

I'm sorry you felt like that: that certainly wasn't my intent. I was
simply trying to point out what others have said: the receiver of a
message is an object, not a variable, and it isn't always possible to
determine an appropriate variable name to use from within a receiver.

Have you considered changing your approach slightly? Rather than making
it assertion-based, you could implement it more like cast-style
checking:

def delete_file(str)
name = cast:)str, String)
# ...

The 'cast' method could then verify its its first parameter was a
kind_of second parameter, and would have the name lying around if it
needed to report an error.

The interpreter takes this kind of approach when ensuring that
parameters have the right behavior. In fact, it goes one better,
supplying the name of a conversion method to use if the object isn't of
the required type:

name = cast:)str, String, :to_str)

You could also do this, making the third parameter optional.

However, I still question whether this is all worthwhile... :)


Cheers

Dave
 
J

Jim Weirich

David King Landrith said:
Let me restate the question:

Whenever a method is called on an object, one and only one symbol is
used to represent the object.

That statement is incorrect.
Is there any way to determine which
symbol was representing the object at the time that the method was
invoked?

Simple answer: NO

Longer answer: Throw an exception and immediately catch it. Ask the
exception for its backtrace and parse the file and line number from the
backtrace (see ri backtrace for details). Then read the file in question
and find the line number of the caller function. Then parse the line of
code and guess at the variable name (if there is one).

If you always call your type checking method in the form

var.should_be(ClassName) # or whatever format you use

then parsing the line of code is not a difficult problem. However, in the
general case it is quite difficult.
 
D

David King Landrith

This looks like a restricted version of Eivind Eklund's types.rb.
Here's
what the author had to say about it:

"The reason I didn't do any particularly public release of it was
that I found that adding type checks to ruby programs were worse
than useless for me - it got in the way of my refactoring, without
catching many bugs."

See http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/84841.

I looked at this before we rolled our own, and decided against using it
because it seemed overkill. We just add xxx.should_be(type, symbol) or
yyy.should_be([type1, type1...], symbol) whenever we want to ensure
failure due to type mixups. We make no attempt in our library to try
to dictate particular combinations parameters, because this seems to me
to go beyond the point of diminishing returns. We haven't found that
it impacts refactoring in the least bit. Since we are dealing with a
very large code base, this helps us in two ways:

1. It often keeps harmful things from happening; e.g.,
#<Module::Object:0x40536218> being inserted into a varchar field
2. In many cases, some error would have occurred as the result of the
wrong type being sent, but forcing it to be an explicit type error
ensures that (a) the error report accurately reflects the problem, and
(b) the error is thrown closer to where it occurred.

Best,

Dave

-------------------------------------------------------
David King Landrith
(w) 617.227.4469x213
(h) 617.696.7133

Life is tough. It's even tougher if you're
an idiot. --John Wayne
 
D

David King Landrith

Now that's helpful. Thx.

I'm sorry you felt like that: that certainly wasn't my intent. I was
simply trying to point out what others have said: the receiver of a
message is an object, not a variable, and it isn't always possible to
determine an appropriate variable name to use from within a receiver.

Have you considered changing your approach slightly? Rather than
making it assertion-based, you could implement it more like cast-style
checking:

def delete_file(str)
name = cast:)str, String)
# ...

The 'cast' method could then verify its its first parameter was a
kind_of second parameter, and would have the name lying around if it
needed to report an error.

The interpreter takes this kind of approach when ensuring that
parameters have the right behavior. In fact, it goes one better,
supplying the name of a conversion method to use if the object isn't
of the required type:

name = cast:)str, String, :to_str)

You could also do this, making the third parameter optional.

However, I still question whether this is all worthwhile... :)


Cheers

Dave
-------------------------------------------------------
David King Landrith
(w) 617.227.4469x213
(h) 617.696.7133

Life is tough. It's even tougher if you're
an idiot. --John Wayne
 
D

David King Landrith

David King Landrith said:


That statement is incorrect.

Fair enough. Does this work?

Whenever a method is called on an object, one and only one expression
or symbol has been resolved to
used to represent the object.

And so:

Is there any way to determine which symbol was representing the
expression or symbol at the time that the method was invoked?

You'll forgive me if I feel like I'm playing twenty questions here.
Perhaps I should be asking: There seems to be some "thing" that the
interpreter determines refers to an object, and there can only be one
of these per method that is invoked. How would we describe this
"thing"?
Simple answer: NO

I can see that this is also the answer to the restated question I ask
above.

Just out of curiosity: At what point does the interpreter discard the
expression that it been evaluated to represent the object?
Longer answer: Throw an exception and immediately catch it. Ask the
exception for its backtrace and parse the file and line number from the
backtrace (see ri backtrace for details). Then read the file in
question
and find the line number of the caller function. Then parse the line
of
code and guess at the variable name (if there is one).

If you always call your type checking method in the form

var.should_be(ClassName) # or whatever format you use

then parsing the line of code is not a difficult problem. However, in
the
general case it is quite difficult.

-------------------------------------------------------
David King Landrith
(w) 617.227.4469x213
(h) 617.696.7133

Life is tough. It's even tougher if you're
an idiot. --John Wayne
 
G

gabriele renzi

il Sat, 3 Apr 2004 04:43:58 +0900, David King Landrith
Since most of our application touches a SQL database in some way (we've
rolled our own ruby database API in C to handle persistence layers and
eliminate the overhead endemic to the dbd/dbi arrangement, since our
tables have 10s of millions of records and we're pushing and pulling
gigabytes of data) destructive errors are a real possibility;

would'nt a proper test-only database fit the need better than type
checking ?

(note that I'd like Soft Typing a-la Jscript.net in ruby, I'm just
looking for some good proof of the need for it :)

Btw, have you listed this cool big ruby-based project on the
RealWorldRuby wiki page? :)
 
M

Mark Sparshatt

David said:
Fair enough. Does this work?

Whenever a method is called on an object, one and only one expression
or symbol has been resolved to
used to represent the object.

And so:

Is there any way to determine which symbol was representing the
expression or symbol at the time that the method was invoked?

You'll forgive me if I feel like I'm playing twenty questions here.
Perhaps I should be asking: There seems to be some "thing" that the
interpreter determines refers to an object, and there can only be one
of these per method that is invoked. How would we describe this "thing"?
This thing is a reference to the receiving object. you can use self#id
to find out this reference but you can't go from that to the variable or
expression that was origionaly used.
I can see that this is also the answer to the restated question I ask
above.

Just out of curiosity: At what point does the interpreter discard the
expression that it been evaluated to represent the object?


Presumably as soon as it has been evaluated.

you want to define a method so that this works

class X
def meth()
p self.magic
end
end

x = X.new
x.meth #=> x

the problem is this is the moral equivelent of

def meth(self)
p self.magic
end

x = x.new
meth(x) #=> x

within meth it just knows there is an object called self, it has no
knowledge of the fact that elsewhere in the program this object is
reffered to as x.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,143
Messages
2,570,822
Members
47,368
Latest member
michaelsmithh

Latest Threads

Top