8. Integration
...but not all of them are JRuby-friendly
(even though JRuby keeps getting better!)
ā¢ Class names and actual classes (beyond jrubyc)
ā¢ Method signatures
ā¢ Overloaded methods
ā¢ Type erasure in generics
ā¢ Subclassing
ā¢ Annotations
ā¢ Executable JAR ļ¬les
ā¢ Legacy applications
10. Correctness
ā¢ Static analysis
ā¢ Refactoring
ā¢ Self-documentation
ā¢ Type errors
ā¢ Unit tests can help...
ā¢ ...but they have to be complete...
ā¢ ...and they donāt cover all possible scenarios...
ā¢ ...and tracking down type errors can be Hell
http://evanfarrer.blogspot.com.es/2012/06/unit-testing-isnt-enough-you-need.html
11. Correctness
ā¢ Use a statically-typed language for critical or
library code
ā¢ Use a dynamically-typed language for high-
level dynamic code and DSLs
http://olabini.com/blog/2008/06/fractal-programming/
12. Performance
JRuby performance is great and getting
better...
(and it doesnāt matter if the application is waiting for the
user 10 times faster)
13. Performance
ā¢ For some tasks, static typing can be faster
ā¢ Heavy computation
ā¢ Method lookup
ā¢ method_missing
ā¢ Some benchmarks:
http://shootout.alioth.debian.org/u32/performance.php
18. Simpliļ¬ed Syntax
ā¢ Case classes
case class Person (ļ¬rstName:String, lastName:String)
ā¢ Type inference
val m = new HashMap[Int, String]
ā¢ No getters / setters
Unless you really need them
ā¢ More ļ¬exible method names (think DSLs)
Use (almost) any character
Translated to legal names in bytecode (i.e., + is $plus, += is $plus$eq)
19. Functional Programming
Mixed OO - Functional model
ā¢ Closures / partial functions
ā¢ foreach, map, fold, ļ¬lter, ...
ā¢ Deļ¬ne your own control structures
ā¢ Immutable eager and lazy values
ā¢ Pattern matching
ā¢ For comprehensions
20. Traits
ā¢ Interfaces with method deļ¬nitions
ā¢ Can be used for mix-ins
ā¢ Calling the previous method in the chain
with no aliasing
ā¢ Dependency injection (ācake patternā)
21. Structural Types
ā¢ Declare what you need, not the type
ā¢ Statically-typed duck typing
class Foo {Ā def x = "Foo.x" }
class Bar {Ā def x = "Bar.x" }
def doIt (arg: { def x:String }) = arg.x
scala> doIt(new Foo)
res0: String = Foo.x
scala> doIt(new Bar)
res1: String = Bar.x
22. Implicits
ā¢ Automatically convert one object to another type
ā¢ Solve some of the same problems as open classes
class MyRichString(str: String) {
Ā Ā def acronym = str.toCharArray.foldLeft("") { (t, c) =>
Ā Ā Ā Ā t + (if (c.isUpperCase) c.toString else "")
Ā Ā }
}
Ā
implicit def str2MRString(str: String) = new MyRichString(str)
scala> "The HitchHiker's Guide To The Galaxy".acronym
res0: java.lang.String = THHGTTG
23. Implicits
In Scala: In Ruby:
implicit def newLT(i: Int) = new { class Fixnum
Ā Ā def <(str: String) = i < str.length Ā Ā alias_method :__old_lt, '<'.to_sym
} Ā Ā def <(target)
Ā Ā Ā Ā if target.kind_of? String
Ā Ā Ā Ā Ā Ā __old_lt__ target.size
scala> 1 < "foo" Ā Ā Ā Ā else
res0: Boolean = false Ā Ā Ā Ā Ā Ā __old_lt__ target
Ā Ā Ā Ā end
scala> 5 < "foo" Ā Ā end
res1: Boolean = true end
http://www.codecommit.com/blog/ruby/implicit-conversions-more-powerful-than-dynamic-typing
24. The Dynamic Trait
ā¢ Similar to method_missing
ā¢ Experimental in 2.9, available in 2.10
object Test extends Dynamic {
Ā Ā def applyDynamic (method:String) (args: Any*) {
Ā Ā Ā Ā println ("%s (%s)".format(method, args.mkString(",")))
Ā Ā }
}
scala> Test.foo("bar",'baz, 1)
foo (bar,'baz, 1)
26. Akka
ā¢ Based on the Actor model (Erlang)
ā¢ Message passing
ā¢ Transparent distribution
ā¢ Messaging system integration
ā¢ AMQP
ā¢ Apache Camel
ā¢ HTTP
ā¢ ...
ā¢ Software Transactional Memory
27. Akka
ā¢ Mikka: Actors in JRuby by Theo Hultberg
(@iconara)
ā¢ Thin wrapper around Akka Java API to
make it more Ruby-like
ā¢ https://github.com/iconara/mikka
ā¢ ...for more info ask Theo!
28. Agenda
ā¢ Why?
ā¢ Why Scala?
ā¢ Calling Scala from JRuby
ā¢ Calling JRuby from Scala
ā¢ Q&A
29. Calling Scala from JRuby
ā¢ Just like Java!
ā¢ JRuby sugar
ā¢ 1.6.0+
ā¢ 1.6.6+
30. Just like Java!
In Scala: In JRuby:
package app.helpers require ājavaā
=> true
import scala.reflect.BeanProperty f = Java::app.helpers.Foo.new
=> #<Java::AppHelpers::Foo:0x325bc91>
class Foo { f.q = "Life, the Universe and Everything"
Ā Ā private var question: String = "" => "Life, the Universe and Everything"
Ā Ā @BeanProperty var a: String = "" f.a = "42"
=> "42"
Ā Ā def questionAndAnswer = "Unknowable" f.q
=> "Life, the Universe and Everything"
Ā Ā def setQ(s:String) = { question = s }
f.a
Ā Ā def getQ = question
=> "42"
}
f.question_and_answer
=> "Unknowable"
https://github.com/jruby/jruby/wiki/CallingJavaFromJRuby
31. Just like Java!
Functions / blocks / closures
In Scala: In JRuby:
package app.helpers f = Java::app.helpers.Foo.new
=> #<Java::AppHelpers::Foo:0x325bc91>
class Foo { f(1, 2, 3) { |x, y| x + y }
Ā Ā def test(x:Int, y:Int, z:Int, => true
Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā f:(Int, Int) => Int) = {
Ā Ā Ā Ā f(x,y) == z
Ā Ā }
}
32. JRuby Sugar - 1.6.0+
Singleton (Scala object) support
Call Singleton methods just like static/class methods
In Scala: In JRuby:
package app.helpers require ājavaā
# => true
object Foo { Java::app.helpers.Foo.test
Ā Ā def test = "Static method" # => āStatic methodā
}
33. JRuby Sugar - 1.6.6+
Operator aliases
$plus -> +
$minus -> -
$div -> /
$plus$eq -> +=
apply (a.k.a. ()) -> []
update (a.k.a. ()=) -> []=
...
There are some caveats... see
https://github.com/jruby/jruby/wiki/Integrating-with-Scala
34. Agenda
ā¢ Why?
ā¢ Why Scala?
ā¢ Calling Scala from JRuby
ā¢ Calling JRuby from Scala
ā¢ Q&A
35. Calling JRuby from Scala
ā¢ JRuby Embed API (RedBridge / JSR-223)
ā¢ Scuby
36. JRuby Embed API
val container = new ScriptingContainer
val receiver = container.runScriptlet("""
# Radioactive decay
def amount_after_years(q0, t)
q0 * Math.exp(1.0 / $half_life * Math.log(1.0/2.0) * t)
end
def years_to_amount(q0, q)
$half_life * (Math.log(q) - Math.log(q0)) / Math.log(1.0/2.0)
end
""")
container.put("$half_life", 24100) // Plutonium
val args = Array[Object](10.0:java.lang.Double, 1000:java.lang.Integer)
val result = container.callMethod("amount_after_years", args, Double.class)
https://github.com/jruby/jruby/wiki/RedBridgeExamples
38. Scuby Goals
ā¢ Thin DSL layer between Scala and JRuby
ā¢ Simplify calling JRuby
ā¢ Calling JRuby should be as transparent as possible
ā¢ Static typing as far as possible
39. Assumptions & Defaults
ā¢ Single JRuby engine
ā¢ For our needs, we donāt need more
ā¢ You donāt have to pass in the engine to every call
ā¢ Singleton interpreter scope (default)
ā¢ Otherwise you can get things like nil != nil
ā¢ Can be changed before ļ¬rst JRuby call
ā¢ Transient local variable behavior (default)
ā¢ Local variables donāt survive multiple evaluations
ā¢ If you need them to persist, store in a Scala val (and pass as
parameter)...
ā¢ ...or change before ļ¬rst JRuby call
42. Example Ruby File
...
Ā Ā module Backend
Ā Ā Ā def self.get_people
Ā Ā Ā Ā Ā Ā # Get data from the backend and return an Array of Person
Ā Ā Ā Ā end
Ā Ā Ā Ā def self.get_data
Ā Ā Ā Ā Ā Ā { :people => get_people, :other_data => get_other_data }
Ā Ā Ā Ā end
Ā Ā Ā Ā def self.get_person(name)
Ā Ā Ā Ā Ā Ā # Get a person's data from the DB and return a Person object
Ā Ā Ā Ā end
Ā Ā Ā Ā def self.get_other_data
Ā Ā Ā Ā Ā Ā # Get some other data that is needed for the app
Ā Ā Ā Ā end
Ā Ā end
end
43. require & eval
import cc.abstra.scuby.JRuby._
// Require a Ruby file from the classpath
require("test")
// Eval a Ruby statement discarding the return value
eval("import Core")
// Eval a Ruby statement that returns a Ruby object
val array = eval[RubyObj]("[]")
// Or with type inference
val array2:RubyObj = eval("[]")
44. Creating Objects
import cc.abstra.scuby._
// Create a Ruby object
val array3 = new RubyObject('Array)
// Create a proxy object for the Ruby BackEnd class
val backend = RubyClass('Backend)
// Create an instance of the Person class
val person = new RubyObject('Person, "Zaphod", "Beeblebrox")
val person2 = RubyClass('Person) ! ('new, "Ford", "Prefect")
45. Calling Methods
Ā Ā Ā Ā // Call a method on a Ruby object (in this case, the Ruby class),
Ā Ā Ā Ā // passing in parameters, and get back another Ruby object
Ā Ā Ā Ā val zaphod = backend ! ('get_person, "Zaphod")
Ā Ā Ā Ā // Call a Ruby method with no parameters
Ā Ā Ā Ā val data = backend ! 'get_data
Ā Ā Ā Ā // Ruby method chaining
Ā Ā Ā Ā val length = backend ! 'get_people ! 'length
Ā Ā Ā Ā // Get a reference to a Ruby method that can later be called
Ā Ā Ā Ā val getPerson = backend --> 'get_person
Ā Ā Ā Ā // Call the method. Returns an AnyRef.
Ā Ā Ā Ā // With the above, these 2 lines are equivalent:
Ā Ā Ā Ā getPerson("Zaphod")
Ā Ā Ā Ā backend('get_person, "Zaphod")
Ā Ā Ā Ā // Call a Ruby method which returns a Java object,
// in a type-safe way
Ā Ā Ā Ā val label = person.send[JLabel]('get_label)
46. Arrays and Hashes
// Access to a Ruby Hash or Array (i.e., anything that implements [])
// and creating a Ruby Symbol using %
val people = data(%('people))
val zaphod2 = people(0)
// Multidimensional Hashes or Arrays (i.e., data["parm1"]["parm2"])
val ford = data(%('people), 1)
// Modify/add an element to a Hash or Array (or anything that
// implements []=)
people(2) = RubyClass('Person) ! ('new, "Arthur", "Dent")
48. Wrapping in Traits
trait Person {
Ā Ā def firstname: String
Ā Ā def firstname_=(f: String): Unit
Ā Ā def lastname: String
Ā Ā def lastname_=(l: String): Unit
Ā Ā def fullname: String
Ā Ā def getLabel: JLabel
}
val zaphod = backend('get_person, "Zaphod").as[Person]
zaphod.firstname = "The Zeeb"
println(zaphod.fullname)
val label = zaphod.getLabel
49. Usage
To use Scuby:
ā¢ Use the Source! (Pull requests welcome)
ā¢ https://github.com/abstracc/scuby
ā¢ Build using Maven
ā¢ Download the compiled artifacts
ā¢ https://oss.sonatype.org/content/repositories/releases/cc/abstra/
pasilla/scuby/0.1.8/
ā¢ You also need scala-library-2.9.2.jar and jruby-complete-1.6.7.jar
ā¢ Add all the .jarās to your CLASSPATH
ā¢ Use Maven (or SBT, Gradle, ...)
ā¢ groupId: cc.abstra.pasilla
ā¢ artifactId: scuby
ā¢ Current version: 0.1.8
50. Future Steps
ā¢ Scala side
ā¢ Ruby collections
ā¢ Java-friendly API
ā¢ Optimization
ā¢ Ruby side
ā¢ Create a Scuby gem
ā¢ FunctionN -> block conversion
ā¢ Wrapping Scala collections
ā¢ Object#to_scala
ā¢ scala top-level function (so we can, i.e., import scala.*)
51. Agenda
ā¢ Why?
ā¢ Why Scala?
ā¢ Calling Scala from JRuby
ā¢ Calling JRuby from Scala
ā¢ Q&A
52. Thank you
Mario Camou
@thedoc
http://github.com/abstracc/scuby
http://github.com/mcamou
http://www.abstra.cc
Special thanks to @MadridJUG