I wonder if there is any real difference between STDIN and $stdin. I do in irb:
STDIN == $stdin
and get back true. Are they just two names for the same thing? Or is there some difference?
From Ruby globals:
STDIN
The standard input. The default value for $stdin.
They are the same object by default.
[1] pry(main)> $stdin.object_id
=> 13338048
[2] pry(main)> STDIN.object_id
=> 13338048
[3] pry(main)> $stdin.object_id == STDIN.object_id
=> true
As #shivam commented, $stdin is a global variable and it may be assigned to something different, while STDIN is a constant.
STDIN is a constant and therefore you'll get a ruby warning if you try to replace it. Otherwise the two are just normal ruby variables in that they can point to the same object (and are by default) and if they do, doing something with one will affect the other variable, but if you assign something else to one of the variables, they will be different.
Standard ruby methods like get will read from $stdin (not STDIN) by default. That means you can override $stdin ($stdout, $stderr) for standard methods and use the constant versions to see what $stdin, $stdout or $stderr originaly were.
Note that overriding $stdin, $stdout, or $stderr won't affect the standard streams of newly spawned programs (the actual filedescriptors 0, 1, and 2 respectively). To do that you'd need to call IO#reopen on the stream you'd want to change, e.g. (assuming the constant version hasn't been forcibly replaced),
STDOUT.reopen("newfile") #Write all output to "newfile" including the output of newly spawned processes (`%x{}`,`system`, `spawn`, `IO.popen`, etc.)
Now with reopen, you can replace the streams only to actual OS-level files/file descriptors (e.g., no StringIO), but if you're on UNIX, there's not much you can't do with OS-level files (you can change them to pipes which you can read elsewhere in your program, for example).
Related
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 years ago.
Improve this question
I've read C2Wiki on Global Variables, and I have three questions about them (at the bottom of this post). The main question is: If Global Variables are so bad, why does Ruby have them?
Also, I've noticed some interesting behaviour regarding Global Variables in Ruby, that causes them to work differently to regular global-level constants.
1. Referencing an undefined Global Variable returns nil. Referencing an undefined global constant returns a NameError:
2.2.3 :001 > $THING
=> nil
2.2.3 :002 > THING
NameError: uninitialized constant THING
from (irb):2
from /Users/makerslaptop82/.rvm/rubies/ruby-2.2.3/bin/irb:15:in `<main>'
2. irb is initialized with both $stdout and STDOUT defined. You can redefine $stdout, and this doesn't affect STDOUT:
2.2.3 :001 > $stdout
=> #<IO:<STDOUT>>
2.2.3 :002 > STDOUT
=> #<IO:<STDOUT>>
2.2.3 :003 > $stdout = IO.new(6)
=> #<IO:fd 6>
2.2.3 :004 > $stdout
=> #<IO:fd 6>
2.2.3 :005 > STDOUT
=> #<IO:<STDOUT>>
My questions are:
If Global Variables are so bad, why does Ruby have them?
Why does referencing undefined Global Variables return nil instead of a NameError? Was this choice deliberate? Why?
Is there some danger to having two virtually-identically-named versions of STDOUT in a single program? (I assume there are other globally-defined objects that this applies to as well)
Global variables are not bad. They're not evil. They're just incredibly, incredibly powerful. Which is why you shouldn't use them.
Global variables are global- they can be accessed and modified anywhere in the code. A single global variable has the potential to affect all of your classes, all of your functions, all of the classes and functions of every single library or dependency you load into your project, and all of the classes and functions of every single project which loads your project as a dependency, as well as the projects that load those projects, and so and and so forth, for ever and always, for the rest of time.
The second people start feeling comfortable using global variables, the namespace gets insanely cluttered and we get conflicts left and right and the stability of the programming language itself is threatened. Which is why the use of global variables is emphatically and repeatedly discouraged.
But global variables are not bad. They're like the highway lanes labeled "for emergency vehicles only," or like those fire-axes behind glass labeled "break glass in case of emergency."
It's entirely possible that at some point, in the distant future, you will have an incredibly unusual situation which merits the use of a single global variable. But that day is not today. And it is probably not tomorrow, or a month from now, or a year from now. Daily life, daily code- it just doesn't call for the unbridled power of a global variable.
$stdout is a great example of why global variables are sometimes important. $stdout is the default stream in ruby- the one where things will print if no other stream is specified. $stdout should be accessible from every class and every function in every library because it acts like a giant funnel, shoveling all output to a single location. The whole world knows and agrees that $stdout exists in ruby, and its uses are well-documented, so its power is well-managed.
This isn't to be confused with STDOUT which is a constant representing the actual pipe which sets up a stream between ruby and its parent program (usually a terminal). $stdout = STDOUT by default, but $stdout can be changed to anything. If you want your program to print to a file, you can change $stdout to a file stream.
I don't think this name choice is confusing for a seasoned rubyist. A variable is designed to be modified and a constant is designed to be constant. The difference between $stdout and STDOUT is that the former can be modified to change the standard output location of your program, and the latter is a constant, always pointing to the stdout stream. The capitalization makes a world of difference and conveys very different meanings.
As for why global constants are uninitialized and global variables are nil, that actually has nothing to do with globals. Ruby automatically initializes all variables as nil. You can easily see this with instance variables such as #foo or ##foo. In almost every situation, an undefined local variable will throw a NameError because ruby cannot tell whether it is a variable or a method. But in strange situations, they too are initialized as nil:
puts foo # => NameError: undefined local variable or method 'foo'
foo = 42 if false
puts foo # => nil
puts bar # => NameError
bar = bar
puts bar # => nil
It was a conscious design choice in Ruby not to automatically initialize constants. Because a constant is, by definition, something which is initialized once and then never changed, it would break the definition for a constant to be nil at first and then a different value later in the code.
I should also mention that global constants are considered acceptable, even among people who tout global variables as bad. The difference is that constants can only be assigned once and generally throw a warning or error if they get assigned again. This protects programmers from situations where conflicting global constants might cause problems.
Here is a simple ruby script, that takes input from a user and provides an output(yes, it will be refactored). I wanted this script to provide output into a text file, rather than console window. That was accomplished, by simply adding $stdout = File.new('out.txt', 'w'), but I thought that this line will just describe a variable which I will use later to tell script to use it to write output into created file.
I cant find much documentation about this method and wondering how does this program knows how to write generated output into that file?
$stdout is a global variable. By default it stores an object of type IO associated with the standard output of the program (which is, by default, the console).
puts is a method of the Kernel module that actually calls $stdout.send() and pass it the list of arguments it receives. As the documentation explains, puts(obj, ...) is equivalent to $stdout.puts(obj, ...).
Your code replaces $stdout with an object of type File that extends class IO. When it is created, your object opens the file out.txt for writing and together with its inheritance from IO it is fully compatible with the default behaviour of $stdout.
Since by default, all the output goes to $stdout, your new definition of $stdout ensures the output is written to the file out.txt without other changes in the code.
$stdout is a global variable (as indicated by $) and according to the documentation, puts is:
Equivalent to
$stdout.puts(obj, ...)
If you assign another object to $stdout, then Kernel#puts will simply send puts to that object. Likewise, print will send write:
class Foo < BasicObject
def puts(*args)
::STDOUT.puts "Foo#puts called with #{args.inspect}"
end
def write(*args)
::STDOUT.puts "Foo#write called with #{args.inspect}"
end
end
$stdout = Foo.new
puts 'hello', 'world'
# Foo#puts called with ["hello", "world"]
print "\n"
# Foo#write called with ["\n"]
Note that if you assign to $stdout, Ruby checks whether the object responds to write. If not, a TypeError will be raised.
It's probably worth highlighting the fact, mentioned by the other posts, that this is a global variable, and modifying it is not thread safe. For instance, if you point $stdout to a new IO stream, anything across the app (on that process thread) that would be logged to stdout will now be logged to your new IO stream. This can lead to multiple streams of unexpected and possibly sensitive input landing in your new IO stream.
Since Ruby supports parallel assignments and automatic value return from functions, almost every assignment and method run ends up creating an output when working on REPLs like IRB and Pry.
Normally I prevent this echo effect by putting a semicolon at the end of each line. For instance:
JSON::parse(very_long_json_string);
This normally prevents REPL echo. But when working with very large enumerables even one mistake can generate enough output to make a mess on the screen and put all my useful command history out of memory before I have the reflex to hit the break.
Is there a way to turn this echo effect off by default in Pry? As mentioned in the comments below (#Stefan), the same can be achieved in IRB by setting conf.echo = false.
In IRB there is:
conf.echo = false
In Pry you could replace the print object with an empty proc:
_pry_.config.print = proc {}
You'll have to store the old print object in order to restore it.
In both cases, the result of the last expression is still available via _
I've been trying to understand the differences between the two, but as of now I have a very rudimentary understanding. ARGV is a subset of IO I believe. I know that ARGV returns an array when called into a Ruby script, but IO does the same thing as well. Can anyone explain this topic to me or direct me to a good explanation? I've searched multiple blogs but to no avail.
Thanks!
ARGV is an array:
> ARGV.class
=> Array
This array contains the command line arguments for your script. For example:
$ cat pancakes.rb
puts ARGV.inspect
$ ruby pancakes.rb -where is house
["-where", "is", "house"]
IO is quite a bit different. IO is:
[...] the basis for all input and output in Ruby. [...]
Many of the examples in this section use the File class, the only standard subclass of IO. The two classes are closely associated. Like the File class, the Socket library subclasses from IO (such as TCPSocket or UDPSocket).
IO is the base class for file-like things in Ruby.
Perhaps you're thinking of ARGF rather than ARGV:
ARGF is a stream designed for use in scripts that process files given as command-line arguments or passed in via STDIN.
The arguments passed to your script are stored in the ARGV Array, one argument per element. ARGF assumes that any arguments that aren't filenames have been removed from ARGV.
[...]
If ARGV is empty, ARGF acts as if it contained STDIN, i.e. the data piped to your script.
So you can use ARGF like an IO that lets you say:
$ your_script some_file
and
$ some_command | your_script
without your_script really having to care about which way it is called.
The IO class is the basis for all input and output in Ruby. An I/O stream may be duplexed (that is, bidirectional), and so may use more than one native operating system stream.
Many of the examples in this section use the File class, the only
standard subclass of IO. The two classes are closely associated. Like
the File class, the Socket library subclasses from IO (such as
TCPSocket or UDPSocket).
The Kernel#open method can create an IO (or File) object for these
types of arguments:
A plain string represents a filename suitable for the underlying
operating system. A string starting with "|" indicates a subprocess.
The remainder of the string following the "|" is invoked as a process
with appropriate input/output channels connected to it. A string equal
to "|-" will create another Ruby instance as a subprocess. The IO may
be opened with different file modes (read-only, write-only) and
encodings for proper conversion. See ::new for these options. See
Kernel#open for details of the various command formats described
above.
Source: http://www.ruby-doc.org/core-2.1.2/IO.html
ARGF is a stream designed for use in scripts that process files given as command-line arguments or
passed in via STDIN.
The arguments passed to your script are stored in the ARGV Array, one
argument per element. ARGF assumes that any arguments that aren't
filenames have been removed from ARGV.
argv → ARGV Returns the ARGV array, which contains the arguments
passed to your script, one per element.
Source: http://www.ruby-doc.org/core-2.1.2/ARGF.html
Ruby has two ways of referring to the standard input: The STDIN constant , and the $stdin global variable.
Aside from the fact that I can assign a different IO object to $stdin because it's not a constant (e.g. before forking to redirect IO in my children), what's the difference between STDIN and $stdin? When should I use each in my code?
If I reassign $stdin, does it affect STDIN?
And does this also apply to STDOUT/$stdout and STDER/$stderr?
If $stdin is reassigned, STDIN is not affected. Likewise $stdin is not affected when STDIN is reassigned (which is perfectly possible (though pointless), but will produce a warning). However if neither variable has been reassigned, they both point to the same IO object, so calling reopen¹ on one will affect the other.
All the built-in ruby methods use $< (a.k.a. ARGF) to read input. If ARGV is empty, ARGF reads from $stdin, so if you reassign $stdin, that will affect all built-in methods. If you reassign STDIN it will have no effect unless some 3rd party method uses STDIN.
In your own code you should use $stdin to be consistent with the built-in methods².
¹ reopen is a method which can redirect an IO object to another stream or file. However you can't use it to redirect an IO to a StringIO, so it does not eliminate all uses cases of reassigning $stdin.
² You may of course also use $</ARGF to be even more consistent with the built-in methods, but most of the time you don't want the ARGF behavior if you're explicitly using the stdin stream.
STDERR and $stderr are pointing to the same thing initially; you can reassign the global variable but you shouldn't mess with the constant. $stdin and STDIN, $stdout and STDOUT pairs are likewise.
I had to change STDERR a couple of times as an alternative to monkey-patching some gems outputting error messages with STDERR.puts. If you reassign with STDERR = $stdout you get a warning while STDERR.reopen('nul', 'w') goes without saying.