Hacker News new | ask | show | jobs
by pmontra 3435 days ago
It takes a while to get used to the idiomatic constructs of a language. Luckily it's much easier than with natural languages.

My first Ruby programs were very Java like. I doubt that my first Java programs were C like, if you use classes and methods it just can't be. No problem with using Python and Ruby together. They are maybe like German and English, close but clearly distinguishable. And Javascript, Perl, PHP, Elixir... too long to write about.

A consequence of multilingualism is that one starts noticing the differences in the implementation of the same features in different languages. Some are smooth, others are frustratingly hard to use or to remember. A quick test on a trivial nuisance, you must not Google it: in Python it's array.join(",") or ",".join(array)? And "1,2,3".split(",") or ",".split("1,2,3")? I remember only that "," goes to the opposite ends in the two expressions and I can't understand why that should be good.

3 comments

The first one is neither - it's string.join(iterable). If you keep that in mind then the design becomes clear - it would have been weirder to force every iterable to have some string-related method. Better to put it on string, where it more reasonably belongs.

The second one is the typical OO pattern where you ask an object to perform some operation on itself. This is how split works in just about every OO language - if you have trouble remembering it, it might be helpful to remember split can be called without any parameters - in that case your alternative variant won't make any sense.

It makes more sense now, thanks. I missed that the argument is an iterable. Ruby's join is a method of Array and of nothing else. Examples with ranges:

Ruby's range must be converted to Array.

    > (1..20).to_a.join(",")
    "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20" 
Python's range must be converted to a list of strings.

    > ",".join([str(i) for i in range(1,21)])
    '1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20'
I've noticed my Elixir experience bleed into how I write Ruby. I'm much more likely to avoid creating objects if I can solve things with a pure function in Ruby now.

And for things like pattern matching, I've played around with doing similar things in Ruby, too. For example, in Elixir you might write a method that should only ever return `:ok`, and a pattern match like this...

    # if :ok, nothing special happens
    # if not :ok, "MatchError" is raised
    :ok = Fooer.foo(foo)
So in Ruby, I played around a watered down equivalent like this

    def ok!(obj)
      raise "match error" unless obj == :ok
    end

    # if :ok, nothing special happens
    # if not :ok, "match error" is raised
    ok! fooer.foo
One day I wrote a bunch of Ruby code of 'ok! <arg>` all over the app, and it made getting the program to run correctly a lot easier (at a time my brain was acclimated to Elixir). I don't know if I'd ever try getting developers on a Ruby project to embrace Erlang/Elixir's "let it crash" mentality, which might not be a great idea for a number of reasons, but it was interesting to me that I had even considered it as an option. Before writing Elixir code, writing a program that crashed on purpose was an alien concept to me.
If you want to create a string from a bunch (iterable? tuple? list?) of smaller strings - shouldn't that be a string method?

If you want to split a given string into smaller strings with an arbitrary delimiter, which instance should you call the method on?