Hacker News new | past | comments | ask | show | jobs | submit login
Confessions of a Ruby Developer Whose Heart was Stolen by Scala (speakerdeck.com)
43 points by YAFZ on June 13, 2013 | hide | past | favorite | 73 comments

They way you'd build large systems in dynamic languages is to break it up into many smaller pieces that work together. This frees you to change parts without worrying about the rest.

To me, this type of development is much more natural and sane than the "one big clusterfuck" type of projects I've seen in Java et.al.

Edit: Also, dynamic languages let you make the tradeof between safety and speed. Sometimes you go slow and steady (simple code, tests..) and sometimes you just want to test something out.

Hm, I don't know what you've seen but I'm pretty sure Java is about breaking up large systems into many smaller pieces that work together, instead of one big clusterfuck. Must be some really badly designed system, more of a programmer's fault than the language itself

True, but isn't it still one big program/project? What I mean was to break it up into many smaller programs and (possibly) projects (think unix process vs. classes =)

Scala is a fantastic language, but my heart seems to resist due to things like this (slide 27/42):

  implicit class RichSeq[A, C[A] <: Seq[A]](underlying: C[A]{
    def cycle: Iterator[A] = {
      lazy val circular: Stream[A] = underlying.toStream #::: circular

This is very dense code, and takes some getting-used-to in order to read. What it achieves is beyond the reach of many languages.

All it does is convert a Seq (sequence) to a lazy stream that will infinitely cycle through the values.

    Seq(1, 2, 3).cycle.take(8).toList
    res3: List[Int] = List(1, 2, 3, 1, 2, 3, 1, 2)
It will work for any seq-like structure (including List. Vector, Queue, etc.)

If you try to use it with anything else, like a Map, it won't compile.

Also, note from my example that it's generic and the resulting List is of the correct type.

Just like novice JavaScript developers struggle with "Why 'this' changes here?", it requires some experience with the language.

> This is very dense code, and takes some getting-used-to in order to read.

I don't think so. It is full of syntactic noise, for what is really just notation for building a cyclic structure.

* type annotations stated explicitly, not inferred

* type variables given multiple times

* too much non-verb, non-noun syntax e.g. `#:::`

* and the actual construction of the cycle is stated imperatively with great ceremony (despite it being an applicative)

It is the opposite of dense.

Brainfuck language is even denser.

The same thing in Haskell:

    cycle seq = circular where circular = seq ++ circular
(or if you want to really golf it)

    cycle = fix . (++)
Ok, to be fair the Scala code is a bit more generic as it works for any abstract sequence, but still, Scala's syntax is awfully heavy compared to Haskell.

That's one reason I still prefer Haskell even though Scala is easier to sneak into enterprise projects thanks to JVM. Not to mention that Haskell gives stronger static guarantees and has a more sophisticated type inference system.

oo. I'd forgotten about fix.

  cycleM = fix . mplus
gives a nice generic version that works on Lists & Sequences but falls afoul of the monomorphism restriction, so it needs a type:

  cycleM :: (MonadPlus m) => m a -> m a
  cycleM = fix . mplus

That's not the sort of thing you'll commonly see in real world Scala code. It's the sort of thing that might be used internally by a library, but not likely something you will come across day-to-day in Scala code. Every language has examples of code where the syntax is hard to follow, but you need to look at common code rather than "ooh let's try some tricks" kind of code.

What makes it a bit more complex than it would be in Ruby is the typesafety (what comes after RichSeq). So it's a bit harder to write such a library, but once it's written it's a breeze to use for users because the compiler tells them right away if something is wrong with the type.

Attention to syntax is what ruby is good at.

Scala, Haskell treat syntax as a chore.

You don't know Haskell.

> take 8 $ cycle [1,2,3]

  cycleM x = x `mplus` (cycleM x)

  take 8 $ cycleM [1,2,3]
might be more generic?

Scala maybe, not Haskell (which barely has any syntax).

As a Ruby developer, I can't get through these sorts of slides. My other languages are C, Go and JavaScript, and the Scala syntax is totally inscrutable to me. Isn't the point of slides presenting something that can be easily absorbed? And I can't just quickly look up these declarations either — Scala is too complex for that given my experience level. Is there a gentle introduction talk for Scala around so I can evaluate the language without putting in a week of learning?

You might try Venkat Subramaniam's Scala for the Intrigued [1]. He's a very good speaker.

Regarding Scala's complexity - some more advanced features are presented in those slides. Imagine watching a talk about Python where they talk about decorators and meta-classes.

[1] https://www.youtube.com/watch?feature=player_embedded&v=grvv...

I'm a Python developer and find a lot of the Ruby criticism in those slides weird. For example you can also monkey patch in Python, but I only recall using it once in the last several years to fix a bug in one method in the standard library. Similarly it isn't a Python pattern to want to write 2.gigabytes.

Are the Ruby complaints in the slides real - do people do those sort of things often and expect other languages to behave like that too? Is that because of the standard library or innate to the language?

I don't know about expecting other languages to behave like [that] too, but the Ruby community certainly does a lot of monkey patching. When I was developing in Ruby I saw this often and it annoyed me a bit.

As a Scala programmer I find Ruby syntax complex and inscrutable, almost like Perl.

As a Python programmer, I agree.

Here's a Ruby snippet. I don't want to pick on this particular project [1], rather, I've found that this is typical of Ruby code:

  state_machine :state, initial: :active do
    after_transition any => :blocked do |user, transition|
      # Remove user from all projects and
      user.users_projects.find_each do |membership|
        return false unless membership.destroy
My conclusion? Ruby's syntax is awful. There are colons, absolute value bars, implications, and who-knows-what-else flying everywhere! It gets worse, elsewhere in the same file there are messy lines like this one with single-arrow implications, question marks and ampersands [2] [3]:

  scope :not_in_project, ->(project) \
    { project.users.present? ?       \
    where("id not in (:ids)", ids: project.users.map(&:id) ) : scoped }
Simple, intuitive syntax? From where I sit, the syntax of Ruby is worse than C++, and approaches Perl levels of awfulness. In most languages, I can at least sort-of grok what's going on from the context when I see unfamiliar operators, but not so in Ruby.

This is a copy-paste of a comment I made [4] weeks ago on another article.

[1] https://github.com/gitlabhq/gitlabhq/blob/4caaea824cf51670d1...

[2] https://github.com/gitlabhq/gitlabhq/blob/4caaea824cf51670d1...

[3] I split the line and inserted backslashes because HN gives me a horizontal scrollbar when it's a single long line; apologies if this transformation isn't legal Ruby, or changes the meaning of the code.

[4] https://news.ycombinator.com/item?id=5784296

I'm a professional ruby programmer and your comments opened my eyes. If you don't know what's going on, then that does look like really icky code.

First off, parenthesis in ruby are optional. So calling a method can be done without parenthesis. The following two lines are the same:

As are these:

    print(1, 2, 3)
    print 1, 2, 3
Here's some bits that might explain better what stuff does:

If you prefix a word with a colon that creates an object of type Symbol, with value "state", which is a bit like the string "state". The difference is that every mention of :state is a reference to the same object, while if you create a string "state", and a bit further do it again, those are two different objects. We use symbols because it runs faster for conditionals etc: to compare two symbols the interpreter only needs to check the reference, while to compare two strings, every character needs to be checked.

    initial: :active
This creates a Hash with one key-value, with key :initial, and value :active, both symbols. This is equivalent to typing :initial => :active which you encounter a bit further up.

    do |var1, var2| .... end
This creates a block, which is like a closure. The variable names between pipes are the arguments this block takes. Any code inside the block is only run when the block is called. In Ruby, every function can have a block passed by adding do ... end to it. Inside this function, the block can be called using the keyword yield, e.g. yield(1,2) to call the block with arguments 1 and 2. The find_each method will loop through every value of the Array it is called on, and run the block once for every value.

The question mark is a valid character for a method name, there's nothing special happening here, present? is just the name of a method. This could easily have been called is_present, or just present.

    a ? b : c
The ternary operator, the same in any language. It translates to "if a, return b, else return c".

    ->(arg1, arg2) { ... }
This creates a lambda, with arguments arg1 and arg2. A lambda is almost the same as a block, so this is almost the same as typing do |arg1, arg2| ... end

This may be the clearest explanation of Ruby syntax I've ever read!

My attempt to parse the above example comes to something like this:

    state_machine(STATE, {"initial" : ACTIVE}, function()
        after_transition({"any" : BLOCKED}, function(user, transition)
                return (membership.destroy ? true : false);
I'm writing in JavaScript because its function notation is way better than Python's lambda syntax. From the parent's explanation, I'm pretty sure this is a valid translation, even though I don't know Ruby. But having three levels of nested anonymous functions really makes the code hard to understand. I'm guessing that this is idiomatic Ruby though, and if you program with the pattern long enough, it gets easier.

OTOH it's still a barrier to entry entirely separate from the syntax -- if the semantics of Ruby code you see "in the wild" is typically this complicated, it's almost as bad as Haskell and its monads! (I have much stronger math chops than most programmers, I've tried to read introductions to monads twice, had them explained to me three separate times on HN, and still don't understand them at all!)

Yep, just about, although if you look closely, the `any` in the original code is not a symbol, but is actually a variable or a method (could be either, we can't know from the sample).

Also, the return in that block would cause an exception, because it doesn't do what the original programmer thinks it does. I guess he never tried out what happens if destroy returns false (which would happen if destroy fails, e.g. because a validation failed).

What you're telling me sounds reasonable, but I thought about it some more, and these rules are so syntactically ambiguous, writing a Ruby parser should be just plain impossible!

If you can call 0-ary functions (functions which take zero arguments) without parentheses, how does Ruby know what a statement as simple as "a = b" does? It must expand internally to something like this (in Python notation):

   a = b() if b.is_function else b
But then if the b() call itself returns a function, then is that function auto-called as well? So we'd have something like this as the Python translation:

   a = b
   while a.is_function:
      a = a()
This can't be right.

And then you get syntactic ambiguities. For example, is the Python translation of the expression x = h-3 (in Ruby) equivalent to (in Python):

(A) x = h-3

(B) x = h(-3)

(C) x = h()-3

(D) x = h()()-3

(E) x = (h-3)()

(F) x = (h()-3)()

Maybe different whitespace, different compile-time definitions, or different run-time values will change the answer! And since the talk says you can monkey-patch Ruby's integer data type, you could even presumably make integers callable so things like "x = (h()-3())()" would be possible!

And then the overloading of the colon and question mark.

Is the expression "k:v" in Ruby a dictionary containing a single key, "k", which is mapped to the value "v"? Or is it a function call of a function called "k" with a single argument, ":v"?

And the ternary operator uses colons too! "a?b:c" could translate as a function called "a?b" being called with a single argument, ":c". Or a dictionary with a key "a?b" which maps to value "c". Or of course the ternary operator! And that's assuming none of the sub-expressions involved are 0-ary functions which are automagically called!

And then what if you want to disable the automagic calling and pass a function object around? Do you have to decorate it with an initial ampersand or something every time you use it? What if you have code like this that puts either a function object or an integer into a variable:

  h = flag ? (&my_function) : 5
Then you want to copy h to the variable y. If you say "y = h" then it does the wrong thing when h is a function, because then h would be auto-called. But if you use the ampersand, you do the wrong thing when h is an integer, because then you would be taking &5 and (in C notation) this would change y from being of type "int" to type "int*". Good grief!

Which all reinforces my original point: Ruby syntax is aggravating! This language is impossible to deal with!

(Sorry for the double reply, but I feel like this comment is different enough from my other reply to merit its own space.)

It's a common joke that Ruby is designed to make it as hard as possible for parsers.

For the code samples going forward, keep in mind that in ruby you don't need a literal return statement to return a value from a method. Just whatever value is last, is returned:

    def val
That method would always return 5.

> But then if the b() call itself returns a function, then is that function auto-called as well?

No, the only way to pass a method is by using method(method_name_here), which returns a Method object. To execute a Method object, you need to call call on it:

     def a
So if you have a method that returns a method, it should not be automatically called, so there's no loop necessary:

     def b

     z = b
Then z is a Method object, namely a.

Some experiments to answer your questions (I admit I wasn't sure for all of them what the outcome would be). IRB is Ruby's repl:

    irb(main):001:0> def a
    irb(main):002:1> 5
    irb(main):003:1> end
    irb(main):019:0> {a: 1}
    => {:a=>1}
    irb(main):020:0> {a(): 1}
    SyntaxError: (irb):20: syntax error, unexpected ':', expecting tASSOC

    irb(main):009:0> def h(num = 10)
    irb(main):010:1> num
    irb(main):011:1> end

    irb(main):012:0> h
    => 10
    irb(main):013:0> h-3
    => 7
    irb(main):014:0> h -3
    => -3
    irb(main):015:0> h - 3
    => 7

    irb(main):001:0> a?b:c
    NameError: undefined local variable or method `c' for main:Object

This is really interesting. I guess some of my examples were relying on using a similar lexer as C -- which you probably couldn't in Ruby. I'll have to think some more about what a Ruby lexer would look like...

But again, it steepens the learning curve -- it's so different from other languages that it's actually kind of hard to immediately see all the implications of "well Ruby's lexer is different than C's lexer".

To be honest to understand those needs only the most basic understanding of Ruby. And I suspect you wouldn't be saying that if they'd used C style syntax for blocks, you'd understand it because that syntax is so prevalent in major languages.

I think you're making the mistake that because Ruby isn't a C-style language, the equivalent of a Latin script language, it's not understandable. It's just disadvantaged that you can't immediately make some assumptions about what the operators do based on previous experience.

* __len__() or len() : More than one way to do it ? Oh my !

* Use setuptools, easy_install, pip while we have fun with our rake and gems.

* lambda : Please have fun, with this vomit of a feature.

* __init__.py explain that to a python beginner.

* Have fun with, { "quote": "shit" } while we use our :symbols

* What scope ?

* Have you migrated code to class Foo(object): yet ?

* How is py3 coming along ? Having fun with the worlds cleanest and bossy language community ?

* Write all your list comprehensions line noise, while we add a elegant method.

I just realized, whitespace is also, precisely the entire content of a pythonista's head.

You have a tumor in your brain.

The point of slides is to act as visual aids for a talk. So without the person talking, in many cases, they're perfectly useless.

As other posters have noted, there are some advance Scala features being used here. It's almost important to note that this talk was given at Scala Days, a conference for Scala programmers, so presumably the target audience is all ready expected to be familiar with Scala (and its syntax). Additionally, given that the speaker appears to be giving reasons why Scala can be a better choice than Ruby, his intended audience may be even smaller: Scala enthusiasts working at a Ruby shop who are trying to convince their coworkers/management to transition from Ruby to Scala... :P

Consider F# then.

For those interested in learning Scala I'd recommend the free chapters from Scala for the Impatient:


Also, _Functional Programming Principles in Scala_ course on Coursera by Martin Odersky (Scala's designer) is very good.


I just finished the most recent session of this class and I found it incredibly frustrating that there was no discussion of the homework assignments after the due dates had passed. What's the point of having homework if there's no way to get the correct answers and get feedback on your solutions?

And take the "in Scala" part of the course title with a grain of salt. You're only taught enough to complete the exercises.

It seemed like most of his slides came down to the old typed/untyped flame war. Yes, in Scala you can look at your objects in an IDE and be told what type they are, in Ruby you can't. Some organizations and people need that, some don't. And yes, it's easier to optimize typed languages. Some applications need that extra speed, most don't.

I'm happy he found a language he enjoys working with, but I doubt this will change anyone's mind...

Somewhat true but I find Scala's inferred typing a surprisingly great compromise between the two.

For example:

val i = 1;

i = "some string" // throws a compiler error, because it knows i is an integer

It's great when you haven't declared the types, you change for example an int to a double or a class to some other class (eg swapping a data structure) and it just flows through the code base without problems like a dynamically typed language.

It can also be pretty useful to look up types when they get complex in the middle of some function, like a Map[List[(String,SomeObject)]] (a map of lists of (String,SomeObject) tuples). Allowing the types to get complex lets me focus on the problem while giving a crutch to quickly remember where it's at half way through (and while finding other methods/source of data) and keep moving towards the solution.

Ruby and Scala are for two different kinds of environments. One is an environment where having less code to maintain (that can also be highly legible) matters and where you have a lot of options. The other is an environment where an edge in performance is more important, but not important enough to write it in an even faster language/not run in the JVM at all.

I noticed a lack of a link to a 1:1 comparison of application code with realistic examples. I think such comparisons and related discussion are often the best way to convince someone to use a language.

And some slides were just blatantly wrong, like Mixin Abuse: apparently that is just a long list of module includes? I have never seen so many module includes in a single class in application code. But, assuming you did have that, you should show what it would look like side-by-side in Scala. In Ruby, there are a lot of options when it comes to including other code or defining code in a class, instance, etc. Those options can lead to much less and more legible code if used correctly.

I remember when people said Java was slow; they made it seem like it was a fad, and no reputable company would use it. And... we see where that went.

Well, of course a classic programming language is better then a script language for majority of tasks. Script languages like JS and Ruby just should not be abused and should only be used as a very thin layer on top. E.g. GUI scripting.

I go the other way -- I write in Python by default, then only go to another language if I specifically need it, for example these scenarios:

(a) Python isn't fast enough, and Pypy doesn't make it fast enough, or isn't a viable option in the target environment. So you write in C, OpenCL or assembly language.

(b) A vital library or other dependency can't talk to Python and you can't quickly find or write a reimplementation or bridge.

(c) Python isn't supported in the target environment, for example, the web browser [1] or the iPhone.

[1] Yes, yes, I know, things like Skulpt and Pyjamas exist. But I think those dependencies are too heavy for a lot of projects.

I would recommend that you immediately inform Yahoo, 37 Signals, Hulu, GitHub, Penny Arcade, and every other Node, Rails, Sinatra, and EventMachine user of this fact!

Also, Tcl/Tk called and wants its use case back.

Why do microsoft and google insist on static compiled languages?

Because they allow us to put very useful limits on the degree to which changes in a large and evolving codebase will violate the expectations of developers. When adding and changing code in large collaborative projects, the primary question in every developer's mind is "OK, what else depends on this, i.e., what is possibly going to break?" This goes back to the old wisdom of separating interface from implementation.

Highly dynamic languages, such as Ruby, certainly have their advantages too. But programs in languages which enable, if not encourage, developers to add new methods to the integer '5' can quickly become very difficult to reason about.

Static, strongly-typed languages also provide other benefits such as much better error checking and compile-time optimization.

Fully agree, I'm a ocamler myself, was trying to make parent op think. Companies with dynamic language codebases should be fearful of the technical debt they've accrued (and hire us static guys to fix it!).

> But programs in languages which enable, if not encourage, developers to add new methods to the integer '5' can quickly become very difficult to reason about.

Can you give me an example of a single ruby developer who thinks this is a good idea when writing new code/a library?

I think probably for every language, every development team needs to have agreements not to do certain things. The probability of a developer doing something unexpected increases exponentially with the number of developers and the amount of code.

It only takes one, but here are a few thousand to start with: https://github.com/search?l=Ruby&q=%22class+Integer%22&ref=a...

Do your projects use any Gems that are pulling in any of this code?

Could they change to do so in the future?

Most importantly: how much effort is it for you to definitively answer this question?

Our task is that of proving a negative (which as we all know is very difficult). Namely that there is no other code that is relying upon the behavior that you are changing. When there are reasonably well-defined interfaces between components it dramatically reduces the possibility space for implicit dependencies and interactions. So this is a slam-dunk case where tools can make our job much easier.

Without tools, we're basically reduced to "verbal lore" and "honor system". Programmers have to rely upon the shared understanding and behavior of other humans in order to reason about their own code.

When I began learning Ruby, this was one of the first exercises in the first chapter of the book I was using. They had you write 3.minutes, 3.hours, 3.seconds, etc. I can find the book if needed. It may be true that strong ruby developers likely will not do this, but then why teach bad practices to beginners?

programs in languages which enable, if not encourage, developers to add new methods to the integer '5' can quickly become very difficult to reason about.

You do know that Scala allows just that, right?

If I knew it at one point, I've forgotten it.

Do you happen to know of any coding standards documents for large projects using Scala?

No, sorry.

I've been thinking about private fields lately.

In Python, a private field starts with an underscore, and someone who knows the culture of Python knows that the initial underscore encodes the notion "This field is not considered to be part of this library's public API, and it may go away or change behavior at any time, not necessarily a major version bump of this library, and if you look at it or change it, you'll be responsible for maintaining your code when we break it. Also it's probably totally undocumented, so you'd better read the library code to make sure it does what you think it does before you use it."

A good developer will weigh the work that can be accomplished today by using the private field against the future consequences of the underscore's admonition, and come to a wise decision -- if (s)he decides to use the field, the Python language will defer to the programmer's human judgment and allow it.

A mediocre developer won't understand the underscore's implications, and will blithely use private and public fields in exactly the same way, because Python won't stop them.

In Java, the language itself will prevent this from occurring -- a private field, in Java, is really private. So the compiler [1] prevents mediocre developers from producing brittle code by referencing private fields everywhere.

If you have a lot of mediocre developers in your organization -- which IMHO tends to happen more in larger organizations -- then you want a stricter compiler to stop them from writing unmaintainable code.

I personally prefer the Python way, simply because I've been bitten by this Java "feature" on multiple occasions -- a third-party library marks some field as private, but I really want to use it, to the extent of being willing to deal with instability by updating my code or freezing the dependency, if necessary. But I can't, without making my own fork of the library.

[1] The runtime also prevents private field access. So even if you bypass the compiler's checks by patching it or hex editing the compiled bytecode, you'll still get runtime errors from trying to read private fields outside the class where they're defined.

Java does not allow using reflection to access private fields !? Dude, just use C#.

You might be able to do it if you replace the SecurityManager or something.

We may laugh now, but it actually seemed like a good idea at the time.

Remember, a big part of Java's early use case was running untrusted remote code ("Applets") in the browesr without prompting the user (a niche now filled by JavaScript [1] and a declining Flash). Which means you really don't want that code to be able to bypass all your security by using the reflection API to read and write things it's not supposed to.

Applets never really caught on, but now the language features are constrained by backward compatibility.

Also, C# isn't supported on Android AFAIK.

[1] Mostly unrelated to Java despite its name; see http://en.wikipedia.org/wiki/Javascript#JavaScript_and_Java

You can access them, it will just throw exceptions you have to catch[1].


Google are trying to use Python as well. But they are probably forcing the best practices as well - otherwise it's a mess.

Those companies are using it properly though, don't they?

Who are "they"?

"Those companies" referring to google and MS.

The speaker pays a lot of attention to implicits in Scala. Well, it's a powerful tool, elegant solutions can be built with it, but you should be careful using them. Implicits bring its own magic and abusing them can pollute your project, make it difficult to understand the code. Maybe the speaker is so attracted to inplicits because they remind him of Ruby's / Rails' magic?

You are correct that implicits are a sharp tool. Thankfully, the Scala community knows that nowadays and they are used for a fairly small number of cases - pimp my library (add methods to Ints, Strings, etc.) and typeclasses.

Can someone comment on the current state of tooling in the Scala world. Last I had tried (some months back), SBT was extremely slow.

Googling about SBT came back with a lot of complaints about the state of scala tooling back then.

I've been using Scala on Android + Intellij IDEA for about the past month after wanting to try something new[1]. Other than having to run it through proguard first, the compile process in Intellij is comparable to how it is with just Java. Scala plays nicely with Android and I have loved using it so far. Makes Android development a bit more fun than with just plain old Java.

[1] https://github.com/yareally/android-scala-intellij-no-sbt-pl...

ah - "Using proguard lets you build Scala without any extra plugins and sbt fiddling".

Seems like the tooling is still one of the more painful aspects of Scala. Kudos to Intellij, -1 to Scala.

Yeah, if I had to manually fiddle around with the SBT build process and manually adding dependencies instead of letting Intellij handle it all, I would be less motivated to want to switch away from Java on Android for sure :).

Excessive configuration to get a new project up in a running is a major demotivator sometimes when you have a new idea and want to just start coding right away.

Do not forget, however, that (for development) you can easily skip the Proguard step if you install the scala libraries on your device directly. Also, setting SBT up is pretty much a one-time thing. Afterwards, you only need to do a few tweaks when starting a new project.

I've used Scala for a couple Android apps in the past... it was great fun to do so! Still, AndroidAnnotations not working with Scala code requires you to rewrite some of their functionality... but you can do that rather easily with Scala's traits etc.

Thanks, I forgot about loading the libraries directly onto my phone for testing. When you say Android Annotations, are you referring to the ones built into java/android (like @TargetApi) or your own custom ones? Just wondering, since I'm about to add ActionBarSherlock to a Scala project and it includes quite a few I'll have to rewrite.

Edit: seems it doesn't like ActionBarSherlock most likely due to that. I get "Error com.actionbarsherlock.R and com.actionbarsherlock.R$xml disgree on InnerClasses attribute"[1].

[1] https://issues.scala-lang.org/browse/SI-1167

I don't believe I've used ABS with Scala before. Shouldn't integrating ABS as an apklib solve this issue though?

Regarding AndroidAnnotations: https://github.com/excilys/androidannotations/wiki

I'll try that option. I was just building it into the project as a separate module dependency out of habit from Java, but no real need to do that.

Ahh, I know of that project. Like it quite a bit. Was just confused over the ambiguity of the term "annotations." Thanks for the followup though.

In case you were curious it was a super vague proguard error that turned out to be the issue. Adding

-keepclassmembers class * extends com.actionbarsherlock.ActionBarSherlock { <init>(android.app.Activity, int); }

fixed it. Ugh :/

I just wonder when someone will build a tool to annotate Ruby, Python source code with var types gathered during run-time.

If C has Valgrind then dynamic typed languages should get something for the types.

PyCharm does this. In addition to doing type inference while you have your project open, you can while debugging it run it and make it collect type information. That's quite a bit slower than usual, but once done you will get extra type hints of possible types passed to your functions.


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact