Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
UC Berkeley Hello (Again) Ruby Things to Review • Syntax & conventions • Class methods/variables vs. Instance methods/variables • Mix-ins and Modules • Closures, Yield, and Blocks CS61A Keywords of the Day • Symbol • Environment Review: Naming Conventions & Syntax • ClassNames class NewRubyProgrammer ... end • method_names and variable_names def learn_conventions ... end • predicate_like_methods? def is_faculty_member? ... end • dangerous_methods! def brainwash_with_ruby! ... end • :symbols favorite_framework = :rails – Symbol or string? use to_sym and to_s to convert between. • SOME_CONSTANTS or OtherConstants – result in warning if reassigned after init Review: Syntax • Syntax features – – – – Whitespace is not significant (unlike Python) Statements separated by semicolons or newlines Statement can span a newline* Parentheses can often be omitted* * when unambiguous to parser; use caution!! raise "D'oh!" unless valid(arg) raise "D'oh!" unless valid arg raise "D'oh!" unless valid(arg) • Advice: use a good text editor Review: Hashes h = {"key" => 1, :value => "foo" } h.has_key?("key") => true h["not a key"] => nil (not an error!) h.delete(:value) => {"key" => 1 } h.merge( {:key2 => "3", "hi" => :blah} ) => {"key"=> 1, "key2" => 3, “hi” => :blah} • Ruby & Rails idioms – omitting braces when a function takes a hash as its last argument – omitting parens around function arguments link_to "Edit student", :controller=>'students', :action=>'edit' link_to("Edit student", {:controller=>'students', :action=>'edit'}) • Warning! if ambiguous parse...better safe than sorry! Administrivia Break • • • • 5um signup Lab 0 Self-diagnostic quiz on web page Books - see course homepage too – more or less required: Agile Web Development with Rails, 2nd ed. – Programming Ruby (free, online at rubycentral.org/book) – or The Ruby Way by Fulton Reminder: Using ri and irb from the shell • irb, interactive Ruby interpreter – follow along with the examples! • ri (Ruby info) is like man – ri Comparable – ri gsub – ri String#gsub • Note, need to be in a shell that has PATH and environment variables set correctly • See www.ruby-doc.org for more good documents UC Berkeley EVERYTHING IS AN OBJECT Everything is an object; (almost) everything is a method call • Everything is an object – Even integers (try 57.methods) – Even nil (try nil.respond_to?(:to_s)) • (almost) every “operator” is really a method call – my_str.length => my_str.send(:length) – mymethod(“foo”) => self.send(:mymethod, “foo”) – 1 + 2 => 1.send(:+, 2) – arr[4] => arr.send(:[ ], 4) – arr[3] = “foo” => arr.send(:[ ]=, 3, “foo”) – if (x == 3) => if (x.send(:==, 3)) Nanoquiz • What happens? x="foo" puts 5+x puts "5"+x Classes & Methods # Methods for MyBank.com class Account @@bank_name = "MyBank.com" # constructor is always called initialize def initialize(starting_balance=0) @balance = starting_balance end # instance methods def balance @balance end def deposit(amount) @balance += amount end def withdraw(amount) @balance -= amount end # A class method def self.bank_name @@bank_name end end Instance methods, not instance variables • Let’s try a few... my_account.@balance my_account.balance my_account.balance = 100 @@bank_name other_account = Account.new(0) other_account.bank_name Account.bank_name • ...got it? Instance variables: shortcut class Foo def initialize(bar,baz) @bar,@baz=bar,baz end def bar ; @bar ; end def baz ; @baz; end def bar=(newbar) ; @bar=newbar ; end def baz=(newbaz) ; @baz=newbaz; end end Instance variables: shortcut class Foo def initialize(bar,baz) @bar,@baz=bar,baz end attr_accessor :bar, :baz end Pitfall class Account def empty_1 balance = 0.0 end # warning!! def empty_2 @balance = 0.0 # OK end def empty_3 self.balance = 0.0 different end end # also ok, but REMEMBER! • a.b means: call method b on object a – a is the receiver to which you send the method call, assuming a will respond to that method does not mean: b is an instance variable of a does not mean: a is some kind of structure of which b is a member Understanding this distinction will save you from much grief and confusion There are (almost) no Loops • “Objects manage their own traversal” • (1..10).each {|x| ... } => range traversal • my_array.each {|elt| ... } => array traversal • hsh.each_key {|key| ... } hsh.each_pair {|key,val| .. } => hash traversal • 10.times {...} => iterator of arity zero • 10.times do ... end {...} is a synonym for do...end Iterators • Consider a simple linear array... – you can enumerate its elements – you can perform operations on the collection (find, delete_if, sort elements, etc.) • Now consider a BinaryTree data structure – instance vars: left child, right child – each child is either a BinaryTree or something else—a leaf node – in principle, should support many of same operations as array! Ruby-think • How would you go about coding a library to support operations like find, delete_if, sort, etc.? • Hint 1 (bad): how does sort() library function work in ANSI C? • Hint 2 (good): what properties of an Array allow you to do these things? – it’s enumerable – its enumerability gives rise to all the other stuff • Can we do that in a generic way for a BinaryTree as well? Ruby-think, cont. • The problem in thinking imperatively is that we don’t know what we will want to do with the elements when we enumerate them. • An iterator separates the concept of “enumerate the elements” from the concept of “doing something” inside that loop. How iterators solve this problem Here’s how to use it... "Armando" "Will" Block of arity 1 "Arthur" • The iterator yields a value to the block • The block executes in the environment in which it was originally defined • The block is called a closure How about sorting, find, ...? • Simple! just include the module Enumerable – Module methods get mixed in to BinaryTree class – Contract: module expects BinaryTree objects to respond_to :each, and it provides the other methods • If you want sorting, include Comparable and make sure the things to be compared respond_to :<=> Mix-in example: Comparable • Example: Define <=> method for your class • include Comparable – methods in Comparable get mixed in (added to) the target class that did the include – methods in Comparable assume that objects of target class respond to <=> – doesn’t actually matter what the class is! • Now, get < <= => > == between? for free – and, your class can now be sorted (by mixing in Enumerable...what do you suppose it assumes?) – Enumerable also provides all?, any?, collect, find, include?, inject, map, partition, .... Duck Typing Makes it Possible • Ruby type = set of values + set of operations • A ruby module defines... – a collection of behaviors – that depend only on the presence of one or more specific existing behaviors QuickTime™ and a TIFF (Uncompressed) decompressor are needed to see this picture. • i.e.: If it looks like a duck and walks like a duck => it responds to the same methods as a duck. • Note, a module ≠ a class – but module methods can get mixed in to classes Blocks • Iterators are just one use of closures • For other interesting ones, check out: – open method of File class – form_tag helper method in Rails • Exercise: implement times in a module n=3 n.times { print "Ho" } => HoHoHo How would you go about this? Summary: Ruby’s Distinguishing Features • Object-oriented with single inheritance – everything is an object – almost everything is a method call – Modules play a role similar to Java’s interfaces and enable “duck typing” • Dynamically typed – Objects have types; variables don’t – very few operators in the language; most are defined as instance methods on objects • Idiomatically, {} and () sometimes optional Variables & Methods • Variables have no type; objects do – variables spring into existence on first assignment • nil,false are Boolean false; everything else true • Everything* is passed-by-reference – can use clone method to effect pass-by-value *except Fixnums... • Defining methods def foo(x); [x,x+1]; end def foo(x) [x,x+1] end def foo(x) return [x,x+1] end Arrays x = [3, 'a', "third", :blah, :last] x[0] => 3 x[-1] => :last x[-2] => :blah x[-3..-1] => ["third", :blah, :last] y = [1,2] y += [3,4] => [1,2,3,4] y << 5 => [1,2,3,4,5] y << [6,7] => [1,2,3,4,5,[6,7]] • Note! These are nearly all instance methods of Array— not language operators! Hashes and function calls • Immediate hash (any object can be a key, any object can be an attribute) my_hsh = {:foo => 1, "x" => nil, 3 => ['a',4]} my_hsh[:nonexistent_key] returns nil • Parens can be omitted from function calls if parsing is unambiguous x = foo(3, "no") x = foo 3, "no" • Braces can be omitted from hash if parsing is unambiguous x = foo( {:a=>1,:b=>2}) x = foo(:a=>1,:b=>2) – easy way to do keyword arguments – Caveat: passing immediates to a function that accepts multiple hashes as its arguments