Objects and Classes8

Ruby is an object-oriented programming language; this chapter will show you what that really means. Like all modern languages, Ruby supports object-oriented notions like classes, inheiritance, and polymorphism. But Ruby goes further than other languages you may have used. Some languages are strict and some are permissive; Ruby is one of the most permissive languages around.

Strict languages enforce strong typing, usually at compile type: a variable defined as an array can't be used as another data type. If a method takes an array as an argument, you can't pass in an array-like object unless that object happens to be a subclass of the array class or can be converted into an array.

Ruby enforces dynamic typing, or duck typing ("if it quacks like a duck, it is a duck"). A strongly typed language enforces its typing everywhere, even when it's not needed. Ruby enforces its duck typing relative to a particular task. If a variable quacks like a duck, it is oneassuming you wanted to hear it quack. When you want "swims like a duck" instead, duck typing will enforce the swimming, and not the quacking.

Here's an example. Consider the following three classes, Duck, Goose, and DuckRecording:

	class Duck
	 def quack
	 'Quack!'
	 end

	 def swim
	 'Paddle paddle paddle…'
	 end
	end

	class Goose
	 def honk
	 'Honk!'
	 end
	 def swim
	 'Splash splash splash…'
	 end
	end

	class DuckRecording
	 def quack
	 play
	 end

	 def play
	 'Quack!'
	 end
	end

If Ruby was a strongly typed language, a method that told a Duck to quack would fail when given a DuckRecording. The following code is written in the hypothetical language Strongly-Typed Ruby; it won't work in real Ruby.

	def make_it_quack(Duck duck)
	 duck.quack
	end

	make_it_quack(Duck.new) # => "Quack!"
	make_it_quack(DuckRecording.new)
	# TypeException: object not of type Duck

If you were expecting a Duck, you wouldn't be able to tell a Goose to swim:

	def make_it_swim(Duck duck)
	 duck.swim
	end

	make_it_swim(Duck.new) # => "Paddle paddle paddle…"
	make_it_swim(Goose.new)
	# TypeException: object not of type Goose

Since real Ruby uses duck typing, you can get a recording to quack or a goose to swim:

	def make_it_quack(duck)
	 duck.quack
	end
	make_it_quack(Duck.new) # => "Quack!"
	make_it_quack(DuckRecording.new) # => "Quack!"

	def make_it_swim(duck)
	 duck.swim
	end
	make_it_swim(Duck.new) # => "Paddle paddle paddle…"
	make_it_swim(Goose.new) # => "Splash splash splash…"

But you can't make a recording swim or a goose quack:

	make_it_quack(Goose.new)
	# NoMethodError: undefined method 'quack' for #
	make_it_swim(DuckRecording.new)
	# NoMethodError: undefined method 'swim' for #

Over time, strict languages develop workarounds for their strong typing (have you ever done a cast when retrieving something from an Java collection?), and then workarounds for the workarounds (have you ever created a parameterized Java collection using generics?). Ruby just doesn't bother with any of it. If an object supports the method you're trying to use, Ruby gets out of its way and lets it work.

Ruby's permissiveness is more a matter of attitude than a technical advancement. Python lets you reopen a class after its original definition and modify it after the fact, but the language syntax doesn't make many allowances for it. It's sort of a dirty little secret of the language. In Ruby, this behavior is not only allowed, it's encouraged. Some parts of the standard library add functionality to built-in classes when imported, just to make it easier for the programmer to write code. The Facets Core library adds dozens of convenience methods to Ruby's standard classes. Ruby is proud of this capability, and urges programmers to exploit it if it makes their lives easier.

Strict languages end up needing code generation tools that hide the restrictions and complexities of the language. Ruby has code generation tools built right into the language, saving you work while leaving complete control in your hands (see Chapter 10).

Is this chaotic? It can be. Does it matter? Only when it actually interferes with you getting work done. In this chapter and the next two, we'll show you how to follow common conventions, and how to impose order on the chaos when you need it. With Ruby you can impose the right kind of order on your objects, tailored for your situation, not a one-size-fits all that makes you jump through hoops most of the time.

These recipes are probably less relevant to the problems you're trying to solve than the other ones in this book, but they're not less important. This chapter and the next two provide a general-purpose toolbox for doing the dirty work of actual programming, whatever your underlying purpose or algorithm. These are the chapters you should turn to when you find yourself stymied by the Ruby language itself, or grinding through tedious makework that Ruby's labor-saving techniques can eliminate. Every other chapter in this book uses the ideas behind these recipes.


Strings

Numbers

Date and Time

Arrays

Hashes

Files and Directories

Code Blocks and Iteration

Objects and Classes8

Modules and Namespaces

Reflection and Metaprogramming

XML and HTML

Graphics and Other File Formats

Databases and Persistence

Internet Services

Web Development Ruby on Rails

Web Services and Distributed Programming

Testing, Debugging, Optimizing, and Documenting

Packaging and Distributing Software

Automating Tasks with Rake

Multitasking and Multithreading

User Interface

Extending Ruby with Other Languages

System Administration



Ruby Cookbook
Ruby Cookbook (Cookbooks (OReilly))
ISBN: 0596523696
EAN: 2147483647
Year: N/A
Pages: 399

Flylib.com © 2008-2020.
If you may any questions please contact us: flylib@qtcs.net