Global variables are bad?

Chaps,

I'm not sure were I have read this but I recall a page or two saying that global variables are bad for some reason. I've overcome my main hurdle, of understanding some of the basics of OO.

There's loads of good code in the following directory:-
/usr/share/doc/ruby-tcltk-1.8.4/tk/sample/demos-en/
which I have used to get me up to speed on widgets and such.

I've seen loads of global variables in
/usr/share/doc/ruby-tcltk-1.8.4/tk/sample/demos-en/...
care to guide a novice on why global variables are used here?
#============================ start of extract ============================

#!/usr/bin/env ruby

# widget --
# This script demonstrates the various widgets provided by Tk,
# along with many of the features of the Tk toolkit. This file
# only contains code to generate the main window for the
# application, which invokes individual demonstrations. The
# code for the actual demonstrations is contained in separate
# ".rb" files is this directory, which are sourced by this script
# as needed.

require 'tk'
# require 'tkafter'

### $DEBUG=1 ##########

···

#----------------------------------------------------------------
# The code below create the main window, consisting of a menu bar
# and a text widget that explains how to use the program, plus lists
# all of the demos as hypertext items.
#----------------------------------------------------------------

# widget demo directory
$demo_dir = File.dirname($0)

# root
$root = TkRoot.new{title "Ruby/Tk Widget Demonstration"}

# tk
$tk_version = Tk::TK_VERSION
$tk_major_ver, $tk_minor_ver = $tk_version.split('.').map{|n| n.to_i}
$tk_patchlevel = Tk::TK_PATCHLEVEL

# tcl_platform
$tk_platform = TkVarAccess.new('tcl_platform')

#
case($tk_version)
when /^4.*/
  $font = TkFont.new('-*-Helvetica-Medium-R-Normal--*-140-*-*-*-*-*-*', nil)
else
  $font = TkFont.new('Helvetica -12')
end

# images
$image = {}
#============================ end of extract ============================

--
John Maclean
MSc (DIC)
07739 171 531

Hi John,

The global vars in the code you quoted were used not as variables, but as
constants. One wouldn't want to pass all those vars in and out of every
subroutine. As used in the code you quoted, I see nothing wrong with them,
because in spirit, if not in the letter of the law, they were used as
constants, never again to be modified.

When I have tons of config info like that I usually wrap it in a single
object, which might be global or local and passed, but it's all in one place.
I find that easier to deal with for config info, even if it's intended to be
constant.

Global variables used as variables can be a debugging nightmare because every
single line of code has write access to them, meaning that if a variable
"goes bad", it's very hard to find where it "went bad". You basically need to
trace through the whole program. Global variables also make a program much
less modular. In my opinion they're the data equivalent of "spaghetti
programming" (http://en.wikipedia.org/wiki/Spaghetti_code\).

SteveT

Steve Litt

slitt@troubleshooters.com

···

On Sunday 08 January 2006 09:33 pm, John Maclean wrote:

Chaps,

I'm not sure were I have read this but I recall a page or two saying that
global variables are bad for some reason. I've overcome my main hurdle, of
understanding some of the basics of OO.

There's loads of good code in the following directory:-
/usr/share/doc/ruby-tcltk-1.8.4/tk/sample/demos-en/
which I have used to get me up to speed on widgets and such.

I've seen loads of global variables in
/usr/share/doc/ruby-tcltk-1.8.4/tk/sample/demos-en/...
care to guide a novice on why global variables are used here?

Interestingly it's allmost universally accepted that Global Variables are
bad ( in the same camp along with GOTO ), yet instance variables are just a
more restrictive variation on the same theme, yet they are best practice :slight_smile:
Guess the functional guys hold the high ground here.

···

On 1/9/06, John Maclean <info@jayeola.org> wrote:

Chaps,

I'm not sure were I have read this but I recall a page or two saying that
global variables are bad for some reason. I've overcome my main hurdle, of
understanding some of the basics of OO.

>
> Chaps,
>
> I'm not sure were I have read this but I recall a page or two saying that
> global variables are bad for some reason. I've overcome my main hurdle, of
> understanding some of the basics of OO.

Interestingly it's allmost universally accepted that Global Variables are
bad ( in the same camp along with GOTO ), yet instance variables are just a
more restrictive variation on the same theme, yet they are best practice :slight_smile:
Guess the functional guys hold the high ground here.

···

On 1/9/06, Lyndon Samson <lyndon.samson@gmail.com> wrote:

On 1/9/06, John Maclean <info@jayeola.org> wrote:

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

What's important here is how easy the code is to work with. Global
variables will usually lead to it being hard to see how different
parts of the program communicate, and make the program behaviour vary
due to a large amount of state stored in a plethora of different
variables. They also often make it hard to change the program, for
instance to have two of something there used to be only one of. So
the critique isn't against "global variables" per se - it's against
global variables used in a way that makes it hard to understand and
change a program. That's the same critique as we have against goto.

Global variables do not always lead to this, and instance variables
can lead to the same problems. And sometimes global variables is the
right solution, leading to a clearer program that's easier to modify.

Just as goto sometimes makes it possible to create programs that's
easier to read. Especially direct implementations of state machines
tend to be easier to read when written using goto than when written
with a separate variable keeping track of the state. I've missed goto
in Ruby a couple of times for this (and before somebody jump in: I
know I can sort of implement it using callcc.)

Eivind.

···

On 1/9/06, Lyndon Samson <lyndon.samson@gmail.com> wrote:

On 1/9/06, John Maclean <info@jayeola.org> wrote:
> I'm not sure were I have read this but I recall a page or two saying that
> global variables are bad for some reason. I've overcome my main hurdle, of
> understanding some of the basics of OO.

Interestingly it's allmost universally accepted that Global Variables are
bad ( in the same camp along with GOTO ), yet instance variables are just a
more restrictive variation on the same theme, yet they are best practice :slight_smile:

Lyndon Samson wrote:

Chaps,

I'm not sure were I have read this but I recall a page or two saying that
global variables are bad for some reason. I've overcome my main hurdle, of
understanding some of the basics of OO.
   
Interestingly it's allmost universally accepted that Global Variables are
bad ( in the same camp along with GOTO ), yet instance variables are just a
more restrictive variation on the same theme, yet they are best practice :slight_smile:
Guess the functional guys hold the high ground here.

The main advantage of instance variables to global variables is that they allow you to scope the variables down to -very- narrow contexts of validity, and they can be hidden outside said scope. If that's what you mean by "more restrictive variation", then scoping is the restriction that matters. And giving context to relate global variables via naming conventions sounds pretty painful.

David Vallner

···

On 1/9/06, John Maclean <info@jayeola.org> wrote:

Lyndon Samson wrote:

>
>
>>Chaps,
>>
>>I'm not sure were I have read this but I recall a page or two saying
that
>>global variables are bad for some reason. I've overcome my main hurdle,
of
>>understanding some of the basics of OO.
>>
>>
>
>
>Interestingly it's allmost universally accepted that Global Variables are
>bad ( in the same camp along with GOTO ), yet instance variables are just
a
>more restrictive variation on the same theme, yet they are best practice
:slight_smile:
>Guess the functional guys hold the high ground here.
>
>
>
The main advantage of instance variables to global variables is that
they allow you to scope the variables down to -very- narrow contexts of
validity, and they can be hidden outside said scope. If that's what you
mean by "more restrictive variation", then scoping is the restriction
that matters. And giving context to relate global variables via naming
conventions sounds pretty painful.

I guess what I was thinking was, conceivably you could have a class with say
100s of methods, all with full access to any ( private/protected/public )
instance variables. How is that different to 100s of functions accessing
global variables?

David Vallner

···

On 1/10/06, David Vallner <david@vallner.net> wrote:

>On 1/9/06, John Maclean <info@jayeola.org> wrote:

--
Into RFID? www.rfidnewsupdate.com Simple, fast, news.

It's not. Both are bad design. However, in the case of the class +
instance variables, the problem is that you shouldn't have hundreds of
(significant[1]) methods in one class, that's a major code stink --
smell isn't a strong enough word.

Jacob Fugal

[1] At peril of reopening the "Array has too many methods" can of
worms; yes, I do like convenience methods; no, I don't think Array has
too many methods, although there are a *few* questionable methods in
Array; yada, yada, yada. The important thing is that convenience
methods *should* be built upon the other methods of the class, and
thus not access the instance variables. They are only there, as the
name implies, for convenience.

···

On 1/9/06, Lyndon Samson <lyndon.samson@gmail.com> wrote:

On 1/10/06, David Vallner <david@vallner.net> wrote:
> The main advantage of instance variables to global variables is that
> they allow you to scope the variables down to -very- narrow contexts of
> validity, and they can be hidden outside said scope. If that's what you
> mean by "more restrictive variation", then scoping is the restriction
> that matters. And giving context to relate global variables via naming
> conventions sounds pretty painful.

I guess what I was thinking was, conceivably you could have a class with
say 100s of methods, all with full access to any
(private/protected/public) instance variables. How is that different to
100s of functions accessing global variables?

Why would you do that? With hundreds of methods, wouldn't these hundreds of
methods tend to categorize in ways that you could split the big class into
smaller ones?

SteveT

Steve Litt

slitt@troubleshooters.com

···

On Monday 09 January 2006 10:15 pm, Lyndon Samson wrote:

I guess what I was thinking was, conceivably you could have a class with
say 100s of methods, all with full access to any ( private/protected/public
) instance variables. How is that different to 100s of functions accessing
global variables?

> I guess what I was thinking was, conceivably you could have a class with
> say 100s of methods, all with full access to any (
private/protected/public
> ) instance variables. How is that different to 100s of functions
accessing
> global variables?

Why would you do that? With hundreds of methods, wouldn't these hundreds
of
methods tend to categorize in ways that you could split the big class into
smaller ones?

Playing Devils Advocate for the sake of the discussion, a quote from MF :slight_smile:

"Another factor is what the language encourages for implementing these
structures. As Charles
Miller<http://fishbowl.pastiche.org/2005/12/09/humane_interfaces&gt;said
"Java's design
*affords* small interfaces, and utility functions provided as static methods
on helper classes. Ruby's design affords larger classes with mixed-in
utility methods."

SteveT

···

On 1/10/06, Steve Litt <slitt@earthlink.net> wrote:

On Monday 09 January 2006 10:15 pm, Lyndon Samson wrote:

Steve Litt
http://www.troubleshooters.com
slitt@troubleshooters.com

--
Into RFID? www.rfidnewsupdate.com Simple, fast, news.

Jacob Fugal wrote:

The main advantage of instance variables to global variables is that
they allow you to scope the variables down to -very- narrow contexts of
validity, and they can be hidden outside said scope. If that's what you
mean by "more restrictive variation", then scoping is the restriction
that matters. And giving context to relate global variables via naming
conventions sounds pretty painful.
     

I guess what I was thinking was, conceivably you could have a class with
say 100s of methods, all with full access to any
(private/protected/public) instance variables. How is that different to
100s of functions accessing global variables?
   
It's not. Both are bad design. However, in the case of the class +
instance variables, the problem is that you shouldn't have hundreds of
(significant[1]) methods in one class, that's a major code stink --
smell isn't a strong enough word.

Jacob Fugal

I'm with Jacob on that one, if you abuse OO, (or rather fail to make proper use of it), you can very well end up with code as evil as script kiddy PHP hacks. Bad code is bad code is bad code, and no language or paradigm will ever prevent people from being horribly bad at it. And vice versa, you can make surprisingly clean procedural code if you enforce granularity and don't rely on global state - GLib comes to mind.

[1] At peril of reopening the "Array has too many methods" can of
worms; yes, I do like convenience methods; no, I don't think Array has
too many methods, although there are a *few* questionable methods in
Array; yada, yada, yada. The important thing is that convenience
methods *should* be built upon the other methods of the class, and
thus not access the instance variables. They are only there, as the
name implies, for convenience.

And at peril of joining sides in a holy war I'm not yet well aware of, I'm taking the stance that people need to distinguish between designing application (internal) code, and designing library (exported) code. The former I prefer maintainable and consistent, the outer, which other people are most likely to make use of, I prefer usable, well supplied with friendly interfaces that provide Sensible Defaults instead of having users of my library understand my Great Plan (tm) - which is something only people that modify a library should care about. The one argument that speaks against many methods in a class is reduced maintainability, but I'll buy that one if I see Array getting convenience methods that aren't implementable with a one-liner.

David Vallner
.NET bashing for fun and profit. (Because SortedLists are IDictionaries now)

···

On 1/9/06, Lyndon Samson <lyndon.samson@gmail.com> wrote:

On 1/10/06, David Vallner <david@vallner.net> wrote:

Lyndon Samson wrote:

Playing Devils Advocate for the sake of the discussion, a quote from MF :slight_smile:
DuckInterface

"Another factor is what the language encourages for implementing these
structures. As Charles
Miller<http://fishbowl.pastiche.org/2005/12/09/humane_interfaces&gt;said
"Java's design
*affords* small interfaces, and utility functions provided as static methods
on helper classes. Ruby's design affords larger classes with mixed-in
utility methods."

Static methods on helper classes? Eww... Lawks, you call those global functions, dearie :stuck_out_tongue_winking_eye: Java is consistent it not being "magic" at any time, and keeping to a very minimal set of well known basic language principles with the good and the bad that brings - the good being it's easy to grok, the bad the severe lack of flexibility there is for consistency's sake.

Then one reason people use the kludgy static methods is because it's usually less typing than properly adding instance methods to your code - laziness is a big motivator of the efforts of man :wink: The other one I can think of is being unable to extend existing classes within Java, but should AspectJ and the like ever get to / already have the dark voodoo of weaving introduction aspects directly into bytecode at startup time, you can arguably do that using some rather trivial AOP if you swing that way.

"The language made me do it" is NOT an excuse for bad design.

David Vallner
.NET bashing for fun and profit (Because SortedLists are IDictionaries now)

Let me reconcile what Martin Fowler is saying there with Steve's
comment. "Ruby's design affords larger classes with /mixed-in utility
methods/" (emphasis added). The size of Array comes mostly from
Enumerable being mixed in. Take away the Enumerable mixin and you have
many fewer methods. Array may override a few of Enumerable's methods
in C for speed, but Array is a special case as a core language
construct, and it still doesn't override the majority. As such,
Array's implementation follows exactly what Steve recommended of
refactoring the bits out into different maintainable chunks. And all
of the methods mixed in by Enumerable are implementation agnostic --
all they require is that you provide an #each method which they build
upon, usually in a one liner. They don't care about or access your
instance variables, which is what this (sub)thread was about in the
first place.

Jacob Fugal

[1] DuckInterface
[2] Humane Interfaces - The Fishbowl

···

On 1/9/06, Lyndon Samson <lyndon.samson@gmail.com> wrote:

On 1/10/06, Steve Litt <slitt@earthlink.net> wrote:
> On Monday 09 January 2006 10:15 pm, Lyndon Samson wrote:
> > I guess what I was thinking was, conceivably you could have a class with
> > say 100s of methods, all with full access to any (
> > private/protected/public) instance variables. How is that different to 100s of
> > functions accessing global variables?
>
> Why would you do that? With hundreds of methods, wouldn't these hundreds
> of methods tend to categorize in ways that you could split the big class into
> smaller ones?

Playing Devils Advocate for the sake of the discussion, a quote from MF :slight_smile: [1]

"Another factor is what the language encourages for implementing these
structures. As Charles Miller[2] said "Java's design *affords* small interfaces,
and utility functions provided as static methods on helper classes. Ruby's
design affords larger classes with mixed-in utility methods."