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 files
• 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. Simplified Syntax
• Case classes
case class Person (firstName:String, lastName:String)
• Type inference
val m = new HashMap[Int, String]
• No getters / setters
Unless you really need them
• More flexible 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, filter, ...
• Define your own control structures
• Immutable eager and lazy values
• Pattern matching
• For comprehensions
20. Traits
• Interfaces with method definitions
• 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 first 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 first JRuby call
41. Example Ruby File
# File test.rb (from the Scuby tests)
module Core
class Person
attr_accessor :firstname, :lastname
def initialize (firstname, lastname)
@firstname = firstname
@lastname = lastname
end
def fullname
"#{firstname} #{lastname}"
end
def get_label
javax.swing.JLabel.new(fullname)
end
end
...
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