Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   Ruby (http://www.velocityreviews.com/forums/f66-ruby.html)
-   -   CORE - Inconsistent Handling of Uninitialized Variables (http://www.velocityreviews.com/forums/t867448-core-inconsistent-handling-of-uninitialized-variables.html)

Ilias Lazaridis 06-15-2011 05:49 PM

CORE - Inconsistent Handling of Uninitialized Variables
 
puts "\n== Testin in MAIN Context =="

local = 'local'
@instance = 'instance'
@@class = 'class'
$global = 'global'

puts "#@instance, #@@class, #$global, #{local}"

begin puts $empty_global == nil rescue puts "undefined" end
begin puts @empty_instance == nil rescue puts "undefined" end
begin puts empty_local == nil rescue puts "undefined" end
begin puts @@empty_class == nil rescue puts "undefined" end


class VarTest
puts "\n== Testin in Class Context =="

local = 'local'
@instance = 'instance'
@@class = 'class'
$global = 'global'

puts "#@instance, #@@class, #$global, #{local}"

begin puts $empty_global == nil rescue puts "undefined" end
begin puts @empty_instance == nil rescue puts "undefined" end
begin puts empty_local == nil rescue puts "undefined" end
begin puts @@empty_class == nil rescue puts "undefined" end

end
#OUTPUT


== Testin in MAIN Context ==
instance, class, global, local
true
true
undefined
undefined

== Testin in Class Context ==
instance, class, global, local
true
true
undefined
undefined

-

The inconsistency:

become nil, do not raise error:
$empty_global
@empty_instance

are undefined, raise an error:
empty_local
@@empty_class


-

Is this a defect or is there an explanation for this behaviour?

..

--
htttp://lazaridis.com

Michael Edgar 06-15-2011 06:05 PM

Re: CORE - Inconsistent Handling of Uninitialized Variables
 
On Jun 15, 2011, at 1:50 PM, Ilias Lazaridis wrote:

> Is this a defect or is there an explanation for this behaviour?



I can speak to local variables; class variables still break my brain a =
little.

Local variables are created during parsing and initialized to nil when =
they
are first encountered. They are available for use at any point in the =
same
scope lexically after their initialization.

This is done because if you attempt to read a local variable lexically =
before it has
been introduced in a local context, we can be sure you have made an =
error.

For global variables and instance variables, we cannot have such lexical
guarantees. While it may be obvious within the scope of a simple program
that a global or ivar has not yet been introduced, it is not a local =
property.
Thus, access is permitted; if the variable has not been initialized, =
then it
is initialized to nil.

The same occurs when Ruby sees an introduced, but uninitialized, local
variable:

def foo(y)
if false
x =3D y
end
p x
end
foo(10)

#=3D> nil

The local is seen at "x =3D y", created in the local variable table, and =
initialized
to nil. The reference to "x" later succeeds because the local has been =
created,
though never initialized.

Michael Edgar
adgar@carboni.ca
http://carboni.ca/=


Ilias Lazaridis 06-15-2011 08:55 PM

Re: CORE - Inconsistent Handling of Uninitialized Variables
 
On 15 , 21:05, Michael Edgar <ad...@carboni.ca> wrote:
> On Jun 15, 2011, at 1:50 PM, Ilias Lazaridis wrote:
>
> > Is this a defect or is there an explanation for this behaviour?

>
> I can speak to local variables; class variables still break my brain a little.

[...] - (explanation)

You have company now, cause all this "breaks my brain", too.

I understand usually better by example, thus I focus on what I've
understood bye the code (and you explanation):

> The same occurs when Ruby sees an introduced, but uninitialized, local
> variable:


The code

> def foo(y)
> * if false
> * * x = y


x is introduced (exists), but not yet assigned (value: nil)

> * end
> * p x
> end
> foo(10)
>
> #=> nil
>
> The local is seen at "x = y", created in the local variable table, and initialized
> to nil. The reference to "x" later succeeds because the local has been created,
> though never initialized.


I understand this.

To simplify (and thus protect our brains), we discuss only locals/
globals

-

I understand the "set_local", and it works as expected.

def set_local(y)
if false
x = y
end
p x #=> nil
#p x2 #=> undefined
end
set_local(10)


def set_global(y)
if false
$x = y
end
p $x #=> nil
p global_variables.include?(:$x) #=> true
p $xx #=> nil
p global_variables.include?(:$xx) #=> true

end
set_global(10)

-

I don't understand, why "p $xx" does not fail with and "not defined"
error.

Technically, the existence of the variable is observable all over the
program.

I don't see the reason why "$xx" is created and set to nil, instead of
throwing an "not defined" error (which I would expect when accessing
an undefined var, could be e.g. a typo of me).

Can this be demonstrated with code?

..

--
http://lazaridis.com

David Masover 06-15-2011 09:52 PM

Re: CORE - Inconsistent Handling of Uninitialized Variables
 
On Wednesday, June 15, 2011 01:05:39 PM Michael Edgar wrote:
> On Jun 15, 2011, at 1:50 PM, Ilias Lazaridis wrote:
> > Is this a defect or is there an explanation for this behaviour?

>
> I can speak to local variables; class variables still break my brain a
> little.


I tend to think class variables are a defect in the first place. If you need
one for some reason, it's usually much better to define it as an instance
variable on the class, rather than as a class variable. That is, instead of:

class Foo
@@bar = true

def hello
if @@bar
puts 'Hello, world!'
else
puts 'Goodbye, world!'
end
end

def depressed!
@@bar = false
end
end


Do something like this instead:


class Foo
self << class
attr_accessor :bar
end

self.bar = true

def hello
if self.class.bar
puts 'Hello, world!'
else
puts 'Goodbye, world!'
end
end

def depressed!
self.class.bar = false
end
end


Of course, that's a terrible example of why you'd ever want to do such a thing
-- there's rarely a reason to have anything approaching class variables -- but
if you need them, I think it makes much more sense to do them that way. This
also keeps them somewhat saner across inheritance, in my opinion. That's the
part that breaks your brain, right? This way, while subclasses seem to inherit
class methods from the superclass, they won't automatically access the same
values, though it's trivial to override them to do that:

class Other < Foo
self << class
def bar
superclass.bar
end
def bar= value
superclass.bar = value
end
end
end

I'd probably use the superclass value as a default until someone overrides it
on this class, so more like:

class Other < Foo
self << class
def bar
@bar || superclass.bar
end
end
end


It's still not as clean as I'd like it to be, but at least this generally
obeys basic concepts I've learned elsewhere which I actually understand. I
have never actually understood class variables.


Ilias Lazaridis 06-18-2011 01:58 AM

Re: CORE - Inconsistent Handling of Uninitialized Variables
 
On 15 , 20:49, Ilias Lazaridis <il...@lazaridis.com> wrote:
[...]

A simplified version, using only locals and globals


def set_local(y)
if false
x = y
end
p x #=> nil
#p xx #=> undefined
end
set_local(10)

def set_global(y)
if false
$x = y
end
p $x #=> nil
p global_variables.include?(:$x) #=> true
p $xx #=> nil
p global_variables.include?(:$xx) #=> true
end
set_global(10)

-

I understand the "set_local", and it works as expected.

I don't understand, why "p $xx" does not fail with an "not defined"
error.

Technically, the existence of the variable is observable all over the
program.

I don't see the reason why "$xx" is created and set to nil, instead of
throwing an "not defined" error (which I would expect when accessing
an undefined var, could be e.g. a typo of me).

..

--
htttp://lazaridis.com


Christopher Dicely 06-19-2011 03:54 PM

Re: CORE - Inconsistent Handling of Uninitialized Variables
 
On Wed, Jun 15, 2011 at 10:50 AM, Ilias Lazaridis <ilias@lazaridis.com> wrote:

>
> Is this a defect or is there an explanation for this behaviour?


Well, I haven't checked the draft ISO standard or RubySpec, but the
behavior is certainly widely known and documented in many Ruby books,
and lots of code relies on the current behavior, and would break if it
were changed. So, I'm going to say its a feature rather than a defect,
whether or not it was originally an intended feature.

And I suspect that its pretty well thought out with the possible
exception of class variable behavior. Globals and locals are often
first assigned remotely from the site where they are used, so calling
them when they haven't been set isn't really a sign of a logic error
-- default to nil makes sense. Local variables are generally (there
are some possible exceptions, I think) set directly in the local
context where they are used, so using one without it being assigned
first is a sign of an error, so not defaulting to nil makes sense.

Class variables probably should behave like instance variables, but
then, class variables are almost never the right tool to use anyway.


Ilias Lazaridis 06-19-2011 04:17 PM

Re: CORE - Inconsistent Handling of Uninitialized Variables
 
On 19 Ιούν, 18:54, Christopher Dicely <cmdic...@gmail.com> wrote:
> On Wed, Jun 15, 2011 at 10:50 AM, Ilias Lazaridis <il...@lazaridis.com> wrote:
>
> > Is this a defect or is there an explanation for this behaviour?

>
> Well, I haven't checked the draft ISO standard or RubySpec, but the

[...]

There is a simplified version, see message from 2011-06-18

..


--
http://lazaridis.com

Michael Edgar 06-19-2011 04:31 PM

Re: CORE - Inconsistent Handling of Uninitialized Variables
 
On Jun 19, 2011, at 11:54 AM, Christopher Dicely wrote:

> Class variables probably should behave like instance variables, but
> then, class variables are almost never the right tool to use anyway.


This is the crux of where Ilias does have a bit of a point: class variables
always require initialization, instance variables and globals do not. The
same rationale for ivars and globals not requiring initialization likely
applies to class variables. I honestly always assumed class variables
behaved like ivars and globals until this thread started.

I imagine the reason behind class variables requiring initialization is
because they're hard enough to use correctly to begin with. However,
changing them to be auto-initialized to `nil` would be more consistent.

I don't care either way - as Chris pointed out, class variables are almost
always wrong. But for long-term internal consistency, it might actually
be worth discussing.

Michael Edgar
adgar@carboni.ca
http://carboni.ca/


Ilias Lazaridis 06-19-2011 07:23 PM

Re: CORE - Inconsistent Handling of Uninitialized Variables
 
(slightly corrected, order of variable types)

puts "\n== Testin in MAIN Context =="

$global = 'global'
@instance = 'instance'
@@class = 'class'
local = 'local'

puts "#$global, #@instance, #@@class, #{local}"

begin puts $empty_global == nil rescue puts "undefined" end
begin puts @empty_instance == nil rescue puts "undefined" end
begin puts @@empty_class == nil rescue puts "undefined" end
begin puts empty_local == nil rescue puts "undefined" end


class VarTest
puts "\n== Testin in Class Context =="

$global = 'global'
@instance = 'instance'
@@class = 'class'
local = 'local'

puts "#$global, #@instance, #@@class, #{local}"

begin puts $empty_global == nil rescue puts "undefined" end
begin puts @empty_instance == nil rescue puts "undefined" end
begin puts @@empty_class == nil rescue puts "undefined" end
begin puts empty_local == nil rescue puts "undefined" end

end

#OUTPUT

== Testin in MAIN Context ==
global, instance, class, local
true
true
undefined
undefined

== Testin in Class Context ==
global, instance, class, local
true
true
undefined
undefined


> The inconsistency:
>
> become nil, do not raise error:
> $empty_global
> @empty_instance
>
> are undefined, raise an error:
> empty_local
> @@empty_class
>
> -
>
> Is this a defect or is there an explanation for this behaviour?



--
http://lazaridis.com


Gary Wright 06-19-2011 10:01 PM

Re: CORE - Inconsistent Handling of Uninitialized Variables
 

On Jun 15, 2011, at 5:00 PM, Ilias Lazaridis wrote:
>=20
> I don't understand, why "p $xx" does not fail with and "not defined"
> error.


Because the parser 'sees' the variable $xx and defines it before "p $xx" =
gets executed.

This behavior is different than the local variable case because global =
variables can be discovered by their name alone (i.e. they start with =
'$'). This is a syntactic property that the parser can take advantage =
of. That property doesn't exist for local variables because, in some =
contexts, they are indistinguishable syntactically from a zero-argument =
method call. Consider these examples separately and not as part of a =
single snippet of code:

a =3D b # 'a' is clearly a local variable while 'b' could be a =
local variable or a zero-argument method call

c =3D d() # 'd()' is clearly a zero-argument method call and *not* a =
local variable, 'c' is a local variable

do_something_with(x,y,z) # x,y, and z could be method calls or =
variables


Gary Wright=



All times are GMT. The time now is 08:23 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.