TEST
Hello, is there Rubyist?
(When I moved) 
From Ruby 
to Scala 
@todesking 
https://www.flickr.com/photos/7armyjmtc/14249465709
Who: 
@todesking 
uses twitter and GitHub 
web: todesking.com
Working at 
Platinum Sponsor
My background 
• Sistem Integrator(2008-2012) 
• Buisiness batches 
• Recommendation system 
• With Java 
• Social game servicer 
• Browser based social game server 
• With Rails 
• DSP servicer 
• Adverting technology(Real-time bidding, user trakcing, machine 
learning) 
• With Scala 
• Vim
What is DSP 
Ad 
Clients 
DSP SSP 
I'm here Pages 
real time bidding(RTB) 
Web 
• "Demand Side Platform" 
• You can find detailed description in at Internet.
Today I NOT talk to: 
• How to build high-performance system 
• DO THE RIGHT THING and KEEP GOING, 
thats all. 
• How to speed up compilation time 
• BUY FASTER MACHINE 
• Whitch is greatest language 
• Every language has own good things 
• BE PEACEFUL
I moved from Ruby 
to Scala, in this April 
• That is smoother than I thought. 
• Basically, Ruby and Scala has common attributes 
• object-oriented and functional paradigm 
• Modern features for productivity and fun
Ruby and Scala is Class-based Object 
Oriented language 
• Class based object oriented language 
class Person(val name:String, val age:Option[Int]) { 
def hello():Unit = { 
class Person < Struct.new(:name, :age) 
def hello 
puts "Hello there, my name is #{name}." 
end 
end 
println(s"Hello there, my name is ${name}.") 
} 
}
At first: Common attributes of Ruby 
and Scala 
• Class based object oriented language with 
functional features 
def sumOfAge(people:Seq[Person]):Int = { 
people.map(_.age).flatten.foldLeft(0)(_ + _) 
} 
def sum_of_age(people) 
people.map(&:age).compact.reduce(0, &:+) 
end
At first: Common attributes of Ruby 
and Scala 
• "Fun" language 
• "Rubyをキメると気持ちいい"(Matz) 
• I can't translate it... 
•  →  
• "Maybe most important is that programming in 
Scala tends to be very enjoyable."
Today's theme: 
How these languages do things 
in different way
Class definition 
class Person(val name:String, val age:Option[Int]) 
val person = new Person("tode sking", Some(31)) 
class Person < Struct.new(:name, :age) 
end 
person = Person.new("tode sking", 31)
Class definition in Ruby 
"class" for class 
definition 
class Person < Struct.new(:name, :age) 
"<" means "extends" Create new instance of Struct 
WHAT?! 
Creating new instance at class definition?!?!
Let's begin most plain case 
class Person 
def initialize(name, age) 
@name = name 
@age = age 
end 
def name; @name; end 
def name=(val); @name = val; end 
def age; @age; end 
def age=(val); @age = val; end 
end 
"def" for method 
definition 
method named "initialize" 
is treated as ctor 
"@name" is instance variable 
getter and setter methods 
Lot of boilerplate
Auto generating accessor method 
in Ruby 
class Person 
def initialize(name, age) ... 
attr_reader :name 
attr_reader :age 
end 
"attr_reader" is keyword for 
generating accessor method 
"attr_writer" and "attr_reader" 
is also available 
NO, actually it is not 
KEYWORD 
It just a METHOD.
Auto generating accessor method 
in Ruby 
attr_accessor :name 
≒ 
define_method("name") { @name } 
define_method("name=") {|val| @name = val } 
≒ 
def name; @name; end 
def mane=(val); @name = val; end
Ruby is DYNAMIC language 
• EVERYTHING is object 
• Class is object too 
• o = Object.new; o.class => Object 
• If you want to create new class, try A = Class.new 
• (assign constant A to fresh class object) 
• To define a method to A, try A.define_method(:foo){...} 
• (actually, define_method is "private". You should 
use A.instance_eval { define_method(:foo) ... })
It called "Macro" in Ruby 
• Such method called "macro"(Actually, it is just a 
method!!) 
• Ruby has no "compile-time". all execution is in 
"runtime"
Defining accessor method: 
Ruby and Scala 
• scala 
• var foo 
• roughly equal to { private[this] var foo_; def foo 
= foo_ } 
• specialized syntax for accessor 
• Ruby 
• attr_* 
• Enhance class definition with DSLs
Auto generating accessor method 
in Ruby 
class Person < Struct.new(:name, :age) 
Create a new instance of 
Struct 
Struct is a kind of Class 
≒ 
PersonBase = Struct.new(:name, :age) 
class Person < PersonBase
Auto generating accessor method 
in Ruby 
Struct.new(:name, age) returns class that like 
class (unnamed) 
def initialize(name, age) 
@name, @age = name, age 
end 
attr_accessor :name 
attr_accessor :age 
# other utility methods... 
end[
Class definition 
class Person(val name:String, val age:Option[Int]) 
val person = new Person("tode sking", Some(31)) 
class Person < Struct.new(:name, :age) 
end 
person = Person.new("tode sking", 31)
Function as value 
• Scala: 
• val f:Int => Int = _ + 1 
• f(1) //=> 2 
• val g:Any => String = _.toString 
• Ruby 
• f = ->(x){x + 1} 
• f.call(1) or f[1] or f.(1) 
• mehod and value is strongly separated 
• g = ->(x){x.to_s}
Functions as value in other 
languages 
• Scheme: f, (f a b) 
• javascript: f, f(a, b) 
• Common Lisp: #'f, (f a b), (funcall #'f (list arg1 
arg2))
Use function as value: Scala 
case 
• def foo(x:Int):String 
• val f = foo // not works 
• val f = foo _ // works 
• def bar(f:Int => String) 
• bar(foo) // works 
• bar(x => x.toString) 
• bar { x => x.toString } 
• bar(_.toString)
Use function as value: Ruby 
case 
• def foo(x) 
• f = method(:foo) 
• f = ->(x){ foo(x) } 
• def bar1(f) 
• def bar2(&f) 
• bar1(f) 
• bar2 {|x| foo(x) } 
• bar2(&f)
Use any object as function 
• [1, 2, 3].map(&:to_s) #=> ["1", "2", "3"] 
• map(&:to_s) 
• It behave like Scala's map(_.toString) 
• If block value is given, Ruby runtime call its 
"to_proc" method and use the result value as 
block. 
• Ruby's Symbol class has to_proc method 
• :to_s.to_proc #=> {|obj| obj.to_s }
Collections 
• Literals 
• Ruby: {}, [] 
• Scala: () 
• Neither list nor hash literals
Collections 
Map HashMap 
TupleN 
LinkedHashMa 
p 
HashMap 
Seq 
immutabl 
e 
LinkedHashMa 
p 
List 
Stack 
mutable 
Buffer 
Traversabl 
e 
Enumerable 
Hash 
{key => value} 
Array 
[1, 2, 3] 
(a, b)
Ruby has "Big" classes 
• "Array" is generic, mutable data structure, it can, 
push/pop, shift/pop, insert, indexed and 
sequential access, and also used as tuple 
• "Hash" is generic, mutable (and only) key-vakue 
map structure in Ruby standard library
Transform collection in Big-class 
style 
• [1, 2, 3].map(&:to_s) #=> ["1", "2", "3"] 
• Ruby has few Big collection classes. Everything 
goes simple.
Transform collection in Scala 
• Iterator[A].map(f:A => B):Iterator[B] 
• List[A].map(f:A => B):List[B] 
• BitSet.map(f:Int => Int):BitSet 
• BitSet.map(f:Int => String):SortedSet[String] 
• Magic "CanBuildFrom" implicit argument is used to 
solve this problem. 
• def map[B, That](f: (Int) ⇒ B)(implicit bf: 
CanBuildFrom[A, B, That]): That 
• Scala used types VERY MUCH.It's cool.
How to ehnahce existing class 
in Scala 
• implicit conversion 
• subclassing
How to ehnahce existing class 
in Ruby 
• subclassing 
• direct modification(simplly 
overwrite/alias_method_chain) 
• define singleton method 
• include/extend 
• refinements
How to handle "non-existens 
value" 
• Scala: Option[T] 
• Ruby: ♥nil♥ 
• false and nil is "falsy". Other values are "truthy". 
• obj.foo if obj # call obj.foo if obj is not nil 
• obj.try(:foo) # same (ActiveSupport feature)
Conclusion 
• Ruby and Scala is very different, but they share 
same goal: be productive, be fun. 
• There are many different approach to solve 
problems.We can learn things and achieve fresh 
surprise from other culture. 
Have a fun with various programming!!
Today I want talk to: 
• Libraries 
• rubygems: High accessibility 
• Source distribution 
• Easy to publish 
• maven repo: Top on Java ecosystem 
• Some impedance missmatch 
• Binary distribution 
• Bit difficult to publish, especially official repo. 
• Build/Task system 
• Rake: Simple scripting with internal DSL 
• Sbt: Type-safe and immutable dependency graph construction with cool := ++= <<= s 
• It's Scala's way!! 
• Community 
• Ruby: Humanity 
• Love emotional context 
• Scala: Types 
• Love Monads !!!!

From Ruby to Scala

  • 1.
  • 4.
  • 5.
    (When I moved) From Ruby to Scala @todesking https://www.flickr.com/photos/7armyjmtc/14249465709
  • 6.
    Who: @todesking usestwitter and GitHub web: todesking.com
  • 7.
  • 8.
    My background •Sistem Integrator(2008-2012) • Buisiness batches • Recommendation system • With Java • Social game servicer • Browser based social game server • With Rails • DSP servicer • Adverting technology(Real-time bidding, user trakcing, machine learning) • With Scala • Vim
  • 9.
    What is DSP Ad Clients DSP SSP I'm here Pages real time bidding(RTB) Web • "Demand Side Platform" • You can find detailed description in at Internet.
  • 10.
    Today I NOTtalk to: • How to build high-performance system • DO THE RIGHT THING and KEEP GOING, thats all. • How to speed up compilation time • BUY FASTER MACHINE • Whitch is greatest language • Every language has own good things • BE PEACEFUL
  • 11.
    I moved fromRuby to Scala, in this April • That is smoother than I thought. • Basically, Ruby and Scala has common attributes • object-oriented and functional paradigm • Modern features for productivity and fun
  • 12.
    Ruby and Scalais Class-based Object Oriented language • Class based object oriented language class Person(val name:String, val age:Option[Int]) { def hello():Unit = { class Person < Struct.new(:name, :age) def hello puts "Hello there, my name is #{name}." end end println(s"Hello there, my name is ${name}.") } }
  • 13.
    At first: Commonattributes of Ruby and Scala • Class based object oriented language with functional features def sumOfAge(people:Seq[Person]):Int = { people.map(_.age).flatten.foldLeft(0)(_ + _) } def sum_of_age(people) people.map(&:age).compact.reduce(0, &:+) end
  • 14.
    At first: Commonattributes of Ruby and Scala • "Fun" language • "Rubyをキメると気持ちいい"(Matz) • I can't translate it... •  →  • "Maybe most important is that programming in Scala tends to be very enjoyable."
  • 15.
    Today's theme: Howthese languages do things in different way
  • 16.
    Class definition classPerson(val name:String, val age:Option[Int]) val person = new Person("tode sking", Some(31)) class Person < Struct.new(:name, :age) end person = Person.new("tode sking", 31)
  • 17.
    Class definition inRuby "class" for class definition class Person < Struct.new(:name, :age) "<" means "extends" Create new instance of Struct WHAT?! Creating new instance at class definition?!?!
  • 18.
    Let's begin mostplain case class Person def initialize(name, age) @name = name @age = age end def name; @name; end def name=(val); @name = val; end def age; @age; end def age=(val); @age = val; end end "def" for method definition method named "initialize" is treated as ctor "@name" is instance variable getter and setter methods Lot of boilerplate
  • 19.
    Auto generating accessormethod in Ruby class Person def initialize(name, age) ... attr_reader :name attr_reader :age end "attr_reader" is keyword for generating accessor method "attr_writer" and "attr_reader" is also available NO, actually it is not KEYWORD It just a METHOD.
  • 20.
    Auto generating accessormethod in Ruby attr_accessor :name ≒ define_method("name") { @name } define_method("name=") {|val| @name = val } ≒ def name; @name; end def mane=(val); @name = val; end
  • 21.
    Ruby is DYNAMIClanguage • EVERYTHING is object • Class is object too • o = Object.new; o.class => Object • If you want to create new class, try A = Class.new • (assign constant A to fresh class object) • To define a method to A, try A.define_method(:foo){...} • (actually, define_method is "private". You should use A.instance_eval { define_method(:foo) ... })
  • 22.
    It called "Macro"in Ruby • Such method called "macro"(Actually, it is just a method!!) • Ruby has no "compile-time". all execution is in "runtime"
  • 23.
    Defining accessor method: Ruby and Scala • scala • var foo • roughly equal to { private[this] var foo_; def foo = foo_ } • specialized syntax for accessor • Ruby • attr_* • Enhance class definition with DSLs
  • 24.
    Auto generating accessormethod in Ruby class Person < Struct.new(:name, :age) Create a new instance of Struct Struct is a kind of Class ≒ PersonBase = Struct.new(:name, :age) class Person < PersonBase
  • 25.
    Auto generating accessormethod in Ruby Struct.new(:name, age) returns class that like class (unnamed) def initialize(name, age) @name, @age = name, age end attr_accessor :name attr_accessor :age # other utility methods... end[
  • 26.
    Class definition classPerson(val name:String, val age:Option[Int]) val person = new Person("tode sking", Some(31)) class Person < Struct.new(:name, :age) end person = Person.new("tode sking", 31)
  • 27.
    Function as value • Scala: • val f:Int => Int = _ + 1 • f(1) //=> 2 • val g:Any => String = _.toString • Ruby • f = ->(x){x + 1} • f.call(1) or f[1] or f.(1) • mehod and value is strongly separated • g = ->(x){x.to_s}
  • 28.
    Functions as valuein other languages • Scheme: f, (f a b) • javascript: f, f(a, b) • Common Lisp: #'f, (f a b), (funcall #'f (list arg1 arg2))
  • 29.
    Use function asvalue: Scala case • def foo(x:Int):String • val f = foo // not works • val f = foo _ // works • def bar(f:Int => String) • bar(foo) // works • bar(x => x.toString) • bar { x => x.toString } • bar(_.toString)
  • 30.
    Use function asvalue: Ruby case • def foo(x) • f = method(:foo) • f = ->(x){ foo(x) } • def bar1(f) • def bar2(&f) • bar1(f) • bar2 {|x| foo(x) } • bar2(&f)
  • 31.
    Use any objectas function • [1, 2, 3].map(&:to_s) #=> ["1", "2", "3"] • map(&:to_s) • It behave like Scala's map(_.toString) • If block value is given, Ruby runtime call its "to_proc" method and use the result value as block. • Ruby's Symbol class has to_proc method • :to_s.to_proc #=> {|obj| obj.to_s }
  • 32.
    Collections • Literals • Ruby: {}, [] • Scala: () • Neither list nor hash literals
  • 33.
    Collections Map HashMap TupleN LinkedHashMa p HashMap Seq immutabl e LinkedHashMa p List Stack mutable Buffer Traversabl e Enumerable Hash {key => value} Array [1, 2, 3] (a, b)
  • 34.
    Ruby has "Big"classes • "Array" is generic, mutable data structure, it can, push/pop, shift/pop, insert, indexed and sequential access, and also used as tuple • "Hash" is generic, mutable (and only) key-vakue map structure in Ruby standard library
  • 35.
    Transform collection inBig-class style • [1, 2, 3].map(&:to_s) #=> ["1", "2", "3"] • Ruby has few Big collection classes. Everything goes simple.
  • 36.
    Transform collection inScala • Iterator[A].map(f:A => B):Iterator[B] • List[A].map(f:A => B):List[B] • BitSet.map(f:Int => Int):BitSet • BitSet.map(f:Int => String):SortedSet[String] • Magic "CanBuildFrom" implicit argument is used to solve this problem. • def map[B, That](f: (Int) ⇒ B)(implicit bf: CanBuildFrom[A, B, That]): That • Scala used types VERY MUCH.It's cool.
  • 37.
    How to ehnahceexisting class in Scala • implicit conversion • subclassing
  • 38.
    How to ehnahceexisting class in Ruby • subclassing • direct modification(simplly overwrite/alias_method_chain) • define singleton method • include/extend • refinements
  • 39.
    How to handle"non-existens value" • Scala: Option[T] • Ruby: ♥nil♥ • false and nil is "falsy". Other values are "truthy". • obj.foo if obj # call obj.foo if obj is not nil • obj.try(:foo) # same (ActiveSupport feature)
  • 40.
    Conclusion • Rubyand Scala is very different, but they share same goal: be productive, be fun. • There are many different approach to solve problems.We can learn things and achieve fresh surprise from other culture. Have a fun with various programming!!
  • 41.
    Today I wanttalk to: • Libraries • rubygems: High accessibility • Source distribution • Easy to publish • maven repo: Top on Java ecosystem • Some impedance missmatch • Binary distribution • Bit difficult to publish, especially official repo. • Build/Task system • Rake: Simple scripting with internal DSL • Sbt: Type-safe and immutable dependency graph construction with cool := ++= <<= s • It's Scala's way!! • Community • Ruby: Humanity • Love emotional context • Scala: Types • Love Monads !!!!

Editor's Notes

  • #4 ăŻă„ă€ă¨ă„ă†ă‚ă‘ă§ă­ă€ăƒ—ăƒŹă‚źăƒłĺ§‹ă‚ă•ă›ăŚă‚‚ă‚‰ăŠă†ă¨ć€ă†ă‚“ă§ă™ă‘ăŠ
  • #5 ăžăšćœ€ĺˆăŤčłŞĺ•ăŞă‚“ă§ă™ăŒă€ă“ăŽäźšĺ ´ăŤRubyを使ったことある方どれくらいいらっしゃいますか? フムー 本日はRubyの話をしに来ました
  • #6 ă¨ă„ă†ă‚ă‘ă§From Ruby to Scalaというタイトルで発表させていただきます。戦争が起きそうなタイトルですけど、RubyはクソだからScalaに行こうぜってわけじゃなくて私がRubyからScalaに行った時の体験談についての話をします!
  • #7 ăŻă˜ă‚ăžă—が皆さん。TwitterやGitHubではtodeskingという名前でやってます。
  • #8 äťŠăŽäť•事はMaverickという会社で、Scalaで広告システムを作ってます。 づなみきMaverickというのはScalaMatsuriのプラチナスポンサーです!!
  • #9 ăžăšç§ăŽăƒăƒƒă‚Żă‚°ăƒŠă‚Śăƒłăƒ‰ăŤă¤ă„がお芹しぞす。 最初はSIerでJavaやってました。推薦エンジンとか、バッチを書くのがメイン。 次の会社ではRuby/Railsでソーシャルブラウザゲームのサーバサイドを担当してました。 今の会社ではScalaで広告システムを作ってます。
  • #10 DSPというのがどういうものかについてはぐぐってください。 簡単に言うとWebの広告配信を代行するサービスです。クライアントから広告を集めて、SSPと呼ばれるサービスの広告枠オークションを通じて広告を配信します。 オークションは誰かが広告枠のあるページを閲覧するたびに行われるため、膨大なリクエストを数十msの遅延で返す必要があります。その制限の中で、広告のCVRを上げるために機械学習など使ったインテリジェントな判断をする必要があるのでむずかしいですね。 まあ今日はそういう話しないんですけどね。
  • #11 ćœŹéĄŒăŤĺ…Ľă‚‹ĺ‰ăŤă€äťŠć—ĽčŠąă™ă“ă¨ăŤă¤ă„ăŚčŞŹć˜Žă—ăžă™ă€‚ まずScalaでハイパフォーマンスシステムを作る方法については触れません。これは一言で言うと「正しいことをやり、それを続ける」ことで実現可能です。遅い処理を書かない、ボトルネックを見つけて最適化する、まずい設計は直す。それを続けるだけです。以上。 みんな大好きなコンパイル時間についての話もしません。速いマシンを買うと改善するという噂があります!! RubyとScalaはどちらが良いのかについても話しません。最近は動的型付けと静的型付けの対立を煽るような動きがありますが、それぞれの言語には独自のいいところがあるので各位仲良くしましょう!!
  • #12 ă•が、私はこぎ4月にRubyからScalaに乗り換えたわけですけど、移行は思ったよりスムーズにいきました。 RubyとScalaは、かなり似た特徴を持っています。 どちらもOOベースで関数型の機能を取り入れていること。そして、生産性と楽しさを重視していること。
  • #13 ăžăšă€ăŠăĄă‚‰ă‚‚ă‚ŻăƒŠă‚šăƒ™ăƒźă‚šăŽă‚Şăƒ–ă‚¸ă‚§ă‚ŻăƒˆćŒ‡ĺ‘č¨€čŞžă§ă™ă€‚ăă‚Œăžă‚ŒăŽč¨€čŞžă§ăťăźĺŒă˜ĺ†…ĺŽšăŽă‚ŻăƒŠă‚šă‚’ĺŽšçžŠă—ăŚăżăžă—ăŸă€‚ăŠăĄă‚‰ăŽč¨€čŞžă‚‚ă€ç°Ąć˝”ăŞč¨˜ćł•ă§ă‚ŻăƒŠă‚šă‚’ĺŽšçžŠă™ă‚‹ăŸă‚ăŽćŠŸčƒ˝ă‚’ĺ‚™ăˆăŚă„ăžă™ă€‚
  • #14 ăžăŸă€é–˘ć•°ĺž‹ăŽćŠŸčƒ˝ă‚’ĺ–ă‚Šĺ…Ľă‚ŒăŚăŠă‚Šă€ç„ĄĺăŽé–˘ć•°ă‚’ă‚¤ăƒłăƒŠă‚¤ăƒłă§ä˝œăŁăŸă‚Šé–˘ć•°ă‚’ĺ€¤ă¨ă—ăŚć‰ąă†ăŸă‚ăŽćŠŸć§‹ă‚’ĺ‚™ăˆăŚă„ăžă™ă€‚
  • #15 ăă—ăŚă€ä¸€ç•ŞăŽĺ…ąé€šç‚šăŻă€ŒćĽ˝ă—ă•ă€ă‚’ă‚łăƒłă‚ťăƒ—ăƒˆăŽä¸€ă¤ăŤă—ăŚă„ă‚‹ă“ă¨ă§ă™ă€‚Rubyの作者であるMatzの”Rubyをキメると気持ちいい"という名言は有名ですし、Martin Odersky氏もScalaの特徴としてScalable, Functionalなどの特徴と並んでFunを挙げています。
  • #16 ĺ…ˆăťăŠç´šäť‹ă—ăŸă‚ˆă†ăŤă€RubyとScalaは似た方向性を持つ言語です。 しかし、その目的を実現するための方法は二つの言語で大きく違います。 今日は、この二つの言語がどのようなアプローチで問題を解決しているのかを紹介しようと思います。
  • #17 ă“ă‚ŒăŻĺ…ˆăťăŠă‚‚ĺ‡şă—ăŸă€Personクラスの定義です。 Scalaの定義は、まあ見たままですね。この一行でnameとageという二つのメンバを持つPersonクラスを定義しなさいという、そういう文です。 さて、Rubyにおいてクラス定義がどのようにされているのか見てみましょう。
  • #18 ă‚ŻăƒŠă‚šĺŽšçžŠăŻclassというキーワードから始めるのはRubyと同様。 小なり記号は、このクラスが右のクラスを継承することを表します。 余談ですが、Scalaでもextendsとかwithとかやめて記号で書きたいですねー。 というわけで、ここではStructをnewした結果を継承したPersonクラスを定義していますね。 なんだって??? 何故かクラス定義時に新しいインスタンスを作っているんですね。 この例は複雑なので、まずは簡単な例から見てみます。
  • #19 ĺ…ˆăťăŠă¨ĺŒă˜ă‚ŻăƒŠă‚šĺŽšçžŠă‚’ă€ăŞă‚‹ăšăĺŸşćœŹćŠŸčƒ˝ăŽăżă§ć›¸ă„ăŚăżăžă—ăŸă€‚ defキーワードでメソッド定義されるのはScalaと同様。initializeという名前のメソッドはコンストラクタになります。 @のついた識別子はインスタンス変数を表します。コンストラクタでnameとageを受け取り、同名のインスタンス変数にセットしています。 その下に並んでいるのはインスタンス変数に対するゲッタとセッタメソッドの定義です。 この単純なやりかただと、まるでジャバのように大量のボイラープレートコードを書く必要があってだるいですね。
  • #20 ăă“ă§ă‚˘ă‚Żă‚ťă‚ľăƒĄă‚˝ăƒƒăƒ‰ăŽĺŽšçžŠă‚’ă‚‚ăŁă¨ĺ˜ç´”ăŤă—ăŸă„ă¨ć€ă„ăžă™ă€‚ 先ほどのメソッド定義の代わりに、attr_readerキーワードを使います。 これを使用することで、指定した名前のセッタとゲッタが自動生成されます。 他にもゲッタのみを生成するattr_reader、セッタのみを生成するattr_writerも用意されています。 さて、今キーワードと言ったけど、それは嘘でした。ここでやっているのは、単なるattr_accessorというメソッドの呼び出しです。
  • #21 ă‚ŻăƒŠă‚šĺŽšçžŠĺ†…ăŤć›¸ă„ăŸĺźăŻScalaだとコンストラクタ扱いになりますが、Rubyの場合はそのクラス定義が読まれたタイミングで評価されます。今の例だと、自分自身、つまりPersonクラスに対してattr_accessorメソッドを呼びます。 このメソッドが呼ばれると、ゲッタとセッタ二つのメソッドが自動的に生成されます。ほぼ同じ処理を手動で書くと、define_methodを呼び出すことでこのように書けます。
  • #22 ă“ă‚ŒăŒRubyの特徴的なところで、この言語においては全てがオブジェクトとして表現されています。全てというのは、つまり、クラスも含みます。 定数AきClassクラスの新しいインスタンスを代入することで新しいクラスが作れるし、クラスAに対してdefine_methodメソッドを呼ぶことで新しいメソッドを定義できます。
  • #23 ă“ぎattr_accesorメソッドのような、クラス定義内で使えるメソッドのことをRubyでは「マクロ」と呼んだりします。 Scala等のコンパイル言語でマクロと言うと、コンパイル時に評価されてASTいじったりする機能のことを指すのでここはRuby文化の特殊なところですね。そもそもRubyにはコンパイル時という概念がないので、他の言語だとマクロで実現するような機能をマクロって読んでるんじゃないかと思います。
  • #24 Scalaでアクセサメソッドを定義しようと思ったら、valやvarキーワードという言語組み込みの機能を使うことになります。これって頑張ればマクロで実現可能なのかというと、たぶん無理な気がします 必要な機能セットをあらかじめsyntaxに含める必要があるScalaと、クラスを動的に操作可能にすることで単なるメソッドで実現可能にするRubyという対比ができそうですね。
  • #25 ćœ€ĺˆăŽäž‹ăŤćˆťă‚Šăžă—ょう。Rubyにおいてはクラス定義も動的に実行されるため、Personの定義時にStructのインスタンスが作成され、継承元として指定されます。
  • #26 ă‚˘ă‚Żă‚ťă‚ľăŽäž‹ă§ăŻăƒĄă‚˝ăƒƒăƒ‰ă‚’ĺ‹•çš„ăŤĺŽšçžŠă—ăŚă„ăžă—ăŸăŒă€Rubyにおいてはクラスそのものも同様に動的生成できます。 Structにアクセサ名を渡してnewすると、先ほどの単純な例で示したのと同じようなクラスが自動生成されます。 このクラスを継承することで、適切なコンストラクタとアクセサを使えるようになってメデタシメデタシとなります。
  • #27 ă¨ă„ă†ă‚ă‘ă§ă€ă‚ŻăƒŠă‚šĺŽšçžŠă‚’äž‹ăŤă—ăŚRubyが動的にクラスを操作可能な言語だということを見てきました。
  • #28 OOの話をしたので次に関数について比べてみます。 ScalaとRubyはどちらも関数を値として扱ったり、インラインで関数を作るための機能を持っています。 変数に束縛した関数を呼ぶ場合、Scalaの場合は通常の関数と同じように呼べますがRubyの場合は関数と値が区別されていて、callメソッドまたはそのエイリアスを呼ぶ必要があります。ドットの後に括弧書く記法は最近のバージョンで入ったみたいなんですが、なんかすごいですねこれ……
  • #29 é–˘ć•°ă‚’ĺ€¤ă¨ă—ăŚć‰ąă†ă¨ăăŽć–šé‡ăŻă€é–˘ć•°ĺž‹č¨€čŞžăŽä¸­ă§ă‚‚ĺˆ¤ć–­ăŒă‚ă‹ă‚ŒăŚă„ăžă™ă€‚ăŸă¨ăˆă°SchemeやJavaScriptのような言語だと、関数名を書けばその関数を値として取得できて、引数を渡せばその関数を呼べるというシンプルで一貫性のある仕様になっています。いっぽうCommonLispだと関数と値の名前空間が分かれていて、関数を値にしたい、あるいは値を関数として呼びたいときは特殊な記法を使う必要があります。 一般的に、利便性を重視しようとするとルールを複雑にする必要が出てくるようです。Scalaでも、名前空間こそ同じですが関数名書いただけだと値として扱ってくれずに_つける必要があったり、このへんは工夫のしどころみたいです。
  • #30 é–˘ć•°ă‚’ĺ€¤ă¨ă—ăŚĺ–ĺž—ă™ă‚‹ć–šćł•ăŤă¤ă„ăŚă‚‚ă†ĺ°‘ă—čŠłă—ăčŚ‹ăŚăżăžă™ă€‚ まずはScalaの事例。fooというIntをとってStringを返す1引数の関数について考えてみます。 Scalaにおいては関数と値の名前空間は同一ですが、f = fooのように、直接関数名を書いてもScalaは値として扱ってくれません。 foo _ のように、識別子の後ろにアンスコをつけることで「その関数を値として取得する」という指定ができます。 また、別の関数にfooを渡す場合については、名前を指定するだけでもいけます。 匿名関数を作る場合は、このようにファットアローで書きます。Scalaの関数呼び出しにおいては、1引数の場合丸括弧のかわりに波括弧も使えます。関数を渡す場合波括弧を使うのが慣習になっているようです。 また、アンダースコアを使うことで「第一引数のtoStringを呼んだ結果」を_.toStringと書けて便利というのもあります。
  • #31 Rubyにおいては、関数を値として取得する場合はmethodメソッドに対象の名前を渡してやる必要があります。実際のコードではあまりこういうことはせず、対象を呼び出す匿名関数を作るケースのほうが一般的だと思いますが。 関数を受け取る関数を書く場合、通常のオブジェクトとして受け取る方法とブロックとして受け取る方法があります。 ブロックというのは関数呼び出し時に一つだけ渡せるコードブロックのことで、呼び出しの後に波括弧でくくった内容が匿名関数として渡せます。値をブロックとして渡したいときは引数に&をつけます。
  • #32 Rubyブロック引数の特徴として、関数以外の値も渡せることが挙げられます。 このコードは数値の配列を文字列の配列にマップしていますが、ここでmapの引数として渡している&:to_sというのはScalaで言うところの_.toString相当です。 RubyにおいてのコロンはScalaのシングルクオート相当で、Symbolリテラルになっています。 さて、シンボルをブロックとして与えると何が起こるんでしょう。実はRubyでは、ブロックとして渡した値に対してto_procメソッドを呼んで、その結果を使用します。Symbolぎto_procは、「引数を一つとって、そのオブジェクトに対して自分と同名のメソッドを呼ぶ」という関数を返すように定義されているため、このようなことが可能になってます。ちょっとわかりにくいですが、:to_sというSymbolをto_procすると、引数のto_procを呼ぶような関数が生成されるということですね。
  • #33 ćŹĄăŤă‚łăƒŹă‚Żă‚ˇăƒ§ăƒłăŤă¤ă„ăŚčŚ‹ăŚăżăžă™ă€‚ Rubyの場合は連想配列と配列のリテラルがあります。 いっぽう、Scalaぎ場合はTupleのリテラルがあります。 最初Scalaに入った時は、これが不思議でした。よく使うコレクションにリテラルが用意されてなくて、Seq()とかMap()とか書かなきゃいけないのはなんでだろうと。
  • #34 ă“こでScalaの標準コレクションを見てみましょう。値を列挙できるTraversable型が元になって、不変と可変それぞれに用途別の細分化されたデータ構造が準備されています。 さて、今度はRubyのコレクションを見てみましょう。 対応関係はこんなかんじです。 あ、TupleはArrayで代用されます。 ScalaきTuple以外のコレクションリテラルがないのは、標準的に使われる唯一の配列型やハッシュ型というのがないせいなんでしょうね。
  • #35 Rubyのライブラリ設計についてよく言われるのが、「大クラス主義」です。Arrayクラスはスタックのようなpush/pop操作、キューのようなshift/pop操作、あるいは任意の位置に要素を挿入したり、インデクスでアクセスしたり列挙したりできて、あと異なる型の値を入れてタプル的にも使われています。実際のところ、Ruby標準ライブラリにはスタックやリンクドリストというクラスはなくて、全部アレイで済ますことになっている。 同様に連想配列についてもミュータブルなハッシュ実装がひとつあるだけで、キーとバリューの組み合わせが必要なところではどこでもこれが使われています。
  • #36 RubyとScalaのコレクション設計で特筆すべきは、型変換の問題です。Rubyにおいては少数の大きいコレクションクラスしかないので、特に複雑なことはありません。たいていのmapメソッドはArrayを返します。
  • #37 ă“ă‚ŒăŒScalaになると話が違います。IteratorをmapするとIteratorになるし、ListをmapするとListが返ります。mapの返り値がコレクションごとに異なるというだけなら、がんばって各クラスごとに特殊化したmapを書いてもいいかもしれませんが、BitSetの中身をIntにマップすると返り値はBitSet、StringにマップするとなんとSortedSetになります。 Scalaにおいては、これらの処理をDRYに書きつつ静的に適切な型が選ばれるように、CanBuildFrom型のimplicit引数が使われています。 このかっこいいmapメソッドのシグネチャを御覧ください。静的に解決できることは極力静的に解決するために、型の力を最大限使おうというのが見て取れます。
  • #38 ă•ăŚă€ćŹĄăŤć—˘ĺ­˜ă‚ŻăƒŠă‚šăŽć‹ĄĺźľăŤă¤ă„ăŚă§ă™ă€‚ Scalaにおいては、implicit conversionであるクラスを拡張する別のクラスに変換してメソッドを追加したり、あるいは既存クラスの挙動をサブクラス化で変えるなどができます。
  • #39 ă—かしRubyの場合は動的にクラスを変更できるので、Scalaよりかなり過激なことが出来ます。 できることの一例としては、既存クラスのメソッドを別のものに差し替えるとか、特異メソッドとかシングルトンメソッドと呼ばれる仕組みで特定のオブジェクトのみメソッドを上書きするということが可能です。 また、includeという機構を使うことでクラスの継承関係に新しいクラスを差し込んだりすることもできます。 既存クラスをそんなダイナミックに書き換えてよく事故らないなという感じですけど、意外と大丈夫です。なぜか。特にRuby on Railsを使うと、文字列や数値といった標準型にも大量の便利メソッドが追加されたりしてダイナミックな感じです。 既存クラスを書き換えることはモンキーパッチングなどと呼ばれています。ライブラリにバグが出る場合にメソッド書き換えて逃げるとか、テスト時だけダミーのメソッドに差し替えるとかできるのではまるとかなり便利です。 あと、refinementsという特定のスコープだけメソッドの書き換えを有効にする仕組みが最近入りました。
  • #40 ćœ€ĺžŒăŤă€ĺ€¤ăŒĺ­˜ĺœ¨ă—ăŞă„ă¨ă„ă†äş‹čąĄă‚’ăŠă†ć‰ąă†ă‹ăŤă¤ă„ăŚčŞŹć˜Žă—ăžă™ă€‚Scalaぎ場合はOptionですね。Rubyの場合はみんな大好きヌルを使います。Rubyにおいてはニルという呼び方なんですが、この値はfalseと合わせて、if文においては偽と判定されます。なのでobjがnilでないときだけメソッドを呼ぶにはif文の中にobjを入れるだけなので簡単ですね。 こういうパターンはあまりによく使うので、Railsで使われてる拡張ライブラリであるActiveSupportではtryメソッドが導入されました。呼びたいメソッド名を渡すことで、nilの場合は何もせず、そうじゃなかったらメソッドを実際に呼ぶというやつです。Rubyではこんなかんじなので、nilに対してメソッドを呼んでNoMethodErrorになる事例が頻発してます。まあ動的言語だと色いろあるよね…… 安全性はともかく、Scalaよりシンプルに書けるというメリットはあります。
  • #41 ă¨ă„ă†ă‚ă‘ă§ă€Scalaとの比較を通してRuby言語の機能を紹介していきました。 なんでも動的に解決するRubyとコンパイル時にすごく色々やるScala、やり方はぜんぜん違うんですけど、生産性を高めて楽しくプログラミングしようというところは似てると思います!! 今日見てきたように、ある問題を解決するための方法は複数あって、どれを選択するかが言語の個性になっています。他の言語を学ぶことによって色々な方法を知るのはおもしろいのでいろんな言語をやりましょう。