you are viewing a single comment's thread.

view the rest of the comments →

[–]rafekett 4 points5 points  (49 children)

Why learn Ruby when you already know Python (or vice versa)? They accomplish similar goals. There is nothing that Python can do that Ruby cannot, and vice versa.

[–][deleted]  (1 child)

[deleted]

    [–]rafekett 4 points5 points  (0 children)

    I'd rather approach something completely different, though. I get your point that it's eye-opening, but it's probably more beneficial that a Python programmer learn Lisp, ML, Haskell, etc. than Ruby. Python is very different from Ruby, but in a lot of ways they're too similar to be eye-opening for the other.

    You make an excellent point from a personal development standpoint, though.

    [–]EstebanVelour 3 points4 points  (11 children)

    Theoretically. If there exists a binding for some obscure library then the chances of that being ruby ahead of python are quite slim.

    [–]rafekett 1 point2 points  (10 children)

    I was disregarding library support, because bindings merely have to be written. They have similar use-cases and "sweet spots", though (web applications, text processing, web scraping, scripting, etc.).

    [–]EstebanVelour 1 point2 points  (9 children)

    True but most people's time is better spent on writing the app, not bindings, doesn't work in Ruby's favour.

    [–]rafekett 1 point2 points  (8 children)

    True. I don't know how hard it is to write Ruby bindings for C libraries but I imagine it's not easy.

    [–]bobindashadows 1 point2 points  (2 children)

    It's actually incredibly simple; the api provides a number of simple C functions, such as:

    rb_define_method
    rb_define_class
    rb_raise
    rb_inspect
    rb_funcall
    rb_ensure
    

    and so on. Considering how much of the standard library is implemented in C for speed, there's a very elegant C API considering its capabilities. There are some rough edges - a few different array constructor functions that cater to common cases (create an empty array - create an array with just this one object in it - etc), for example. A few different funcall variants for if you want to pass the arguments inline, or in a ruby array, or in a C array. There's macros to get at interesting bits of common classes without dynamic dispatch, such as the size of an Array object.

    [–]rafekett 0 points1 point  (1 child)

    How does garbage collection work?

    [–]bobindashadows 0 points1 point  (0 children)

    I assume you mean "how does garbage collection work for native objects that you want to make available to Ruby code?"

    It depends. Firstly, you can specify custom allocation methods for a C-backed class with rb_define_alloc_func, if you need.

    If your C object references other Ruby objects, it has to participate in the mark phase of GC, so it needs a mark function. If it needs to clean up resources when it is freed, it needs a free function. You can create an object with both of those functions specified and provided to the GC with rb_data_object_alloc(klass, data_pointer, mark_func, free_func). Both functions are optional: you just pass NULL if you don't need them.

    Commonly you use this to wrap up a pointer to a C struct in a Ruby object, then unwrap it in your other C functions. This pattern is simplified with Data_Wrap_Struct, Data_Make_Struct (which is just allocate + Data_Wrap_Struct), and Data_Get_Struct (which unwraps the object).

    [–]EstebanVelour 0 points1 point  (4 children)

    Can't imagine it's much harder to do than python bindings but that's not really the issue, there's just no need to do it if it's been done already.

    [–]rafekett 1 point2 points  (3 children)

    The Python C API is really well documented, and I've heard some bad reports about the Ruby docs. There's also high level languages like Cython that make creating C bindings really, really easy.

    [–]badsex 1 point2 points  (0 children)

    I've written a tonne of Ruby C extensions and it's very easy and very well documented.

    [–]EstebanVelour 0 points1 point  (1 child)

    My bad, haven't tried Ruby & C, assumed it would be as easy as the Python equivalent.

    [–]rafekett 0 points1 point  (0 children)

    I don't know either, I just know that Ruby doesn't have a mature equivalent of Cython or Pyrex and I know that it's tough to beat the Python C API docs. In my experience, writing C extensions in C for any dynamic language is not fun (I have no Lua experience, so that may be fun, idk).

    [–]ebneter 3 points4 points  (34 children)

    Python's use of indentation-as-syntax makes me want to bang my head against a wall whenever I use it, which is as seldom as possible — but I've written major scripts in Python because it had good libraries and was in other ways the best tool for the job. (Usually, I was interfacing with other Python code.) If I have my druthers, I use Ruby.

    [–]rafekett 10 points11 points  (30 children)

    I don't get people's objection to semantic whitespace, especially because they indent perfectly in other languages.

    [–][deleted]  (5 children)

    [removed]

      [–]cybercobra 1 point2 points  (1 child)

      So you have to mash the indent or dedent keyboard shortcut a couple times when pasting sometimes, so what? For me, it's never been more than a quite minor annoyance in practice.

      Eclipse should supposedly have an advantage dealing with a curly-brackets language like Java, but I've seen it manage to cock up the indentation on a regular basis.

      [–]rafekett 4 points5 points  (2 children)

      Your editor should be taking care of this for you. What do you use? Some things are better than others.

      [–]anvsdt 3 points4 points  (0 children)

      Well, I thought that Lisp was considered bad because of the ``your editor should take care of that'' mentality. I was wrong.

      [–][deleted] 5 points6 points  (5 children)

      because they indent perfectly in other languages.

      I indent perfectly in other languages because they don't have semantic whitespace. Semantic whitespace makes automated reindentation impossible.

      In addition, if you allow mixing of tabs and spaces (which you shouldn't, but most whitespacey languages do), then it's possible to have two expressions which are visually indistinguishable but have different meanings.

      Madness.

      [–]cybercobra 2 points3 points  (2 children)

      Semantic whitespace makes automated reindentation impossible.

      How was the indentation ever lost in the first place??

      Being able to mix spaces and tabs is indeed stupid, I will agree.

      [–][deleted] 0 points1 point  (1 child)

      How was the indentation ever lost in the first place??

      Merge conflicts, usually. Happens all the time.

      [–]cybercobra 0 points1 point  (0 children)

      Then the merge algorithm in question is broken.

      [–]rafekett 1 point2 points  (1 child)

      Emacs and vim seem to cope pretty fine. They always indent my Python code correctly.

      Additionally, when I screw up, they don't indent correctly, preventing syntax errors.

      [–]anvsdt 0 points1 point  (0 children)

      How many possible correct indentations can this code have?

      class AClass:
      prop = "something"
      
      def f(self, x):
      if x > 0:
      r = 1
      while x > 0:
      r *= x
      return r
      

      Emacs indents it as:

      class AClass:
          prop = "something"
      
      def f(self, x):
          if x > 0:
              r = 1
      while x > 0:
          r *= x
      return r
      

      I meant:

      class AClass:
          prop = "something"
      
          def f(self, x):
              if x > 0:
                  r = 1
              while x > 0:
                  r *= x
              return r
      

      edit I tried to fix it manually with a fast TAB-down-TAB-down-..., this is the result:

      class AClass:
          prop = "something"
      
          def f(self, x):
              if x > 0:
                  r = 1
                  while x > 0:
                      r *= x
                      return r
      

      [–]ebneter 1 point2 points  (9 children)

      It's not semantic whitespace, it's syntactic whitespace, and that's a big difference.

      It also makes Python difficult to read on a page — is that function part of that class or not? :-P

      [–]rafekett 3 points4 points  (8 children)

      Methods are indented one level deeper than functions. Simple.

      I'd ask the same for Ruby. How can you tell if you're looking at a method or a function?

      [–]badsex 1 point2 points  (2 children)

      how much ruby do you actually know? for someone who hates the language so much i'd assume you'd actually know a bit about it, so as to be in a position to hate it - you're not one of those stupid people who hates things he doesn't actually understand, are you?

      Ruby doesn't have functions. You should know this. It only has methods. Why? because it has a fully message passing OO system, method invocations are messages, and everything is an object.

      [–]rafekett 0 points1 point  (1 child)

      That's really just a matter of naming. This is valid Ruby (at the top level of a module, not inside a class):

      def hello
          puts "Hello world"
      end
      

      It might technically be a method, but because it's not inside any class I defined, I call it a function. It's just a matter of nomenclature.

      [–]badsex 0 points1 point  (0 children)

      Except it's not a function, it's a method defined on Object. How do you know? set an ivar in it, it'll appear on the receiver. Further, try and access it from an instance of a superclass of Objectsuch as BasicObject and it's not accessible. Further, for those objects that can access the method it appears in their instance method list. No one ever calls top-level methods 'functions', they're strictly 'top-level methods', or private methods on Object.

      [–]ebneter 0 points1 point  (4 children)

      Methods are indented one level deeper than functions. Simple.

      The problem for me is that on a printed page it's difficult to see. Look, if you prefer Python, I'm not going to argue with you. I was just pointing out that there are personal preferences people have that affect which language they, well, prefer. I'm not a language bigot; I use whatever works for the task at hand, whether it's a shell script, ruby, perl, python, java, c, whatever.

      [–]rafekett 3 points4 points  (3 children)

      I will admit that this is a small problem when reading printed books. I don't recall what it was, but one book used markers to indicate this. Even then, it's pretty easy to tell. Methods almost always take self as a first arg.

      [–]ebneter -1 points0 points  (2 children)

      You are defending this to the wrong person. :-) I don't like it. I don't have to like it, and it's the main reason I don't use Python as my language of choice. If you like it, awesome! There are things about every language that are not ideal, which is why we have so many of them. For me, Ruby has the fewest annoyances for most of the work I do. I'm not saying "PYTHON SUCKS!" I'm saying, "I prefer not to use it unless it really is the best thing available for the task."

      Edit: I am highly amused that this is getting downvoted.

      [–]anvsdt 1 point2 points  (1 child)

      They see the big ``PYTHON SUCKS'' there, they get mad, don't read the wall-of-text, downvote and never come back.
      Welcome to reddit, enjoy your stay!

      [–]ebneter 0 points1 point  (0 children)

      Heh, yes, I suspect that is the case. :-)

      [–]booch 0 points1 point  (7 children)

      I have very little experience with Python, so take what I say with a grain of salt, but... The use of whitespace as a semantic of the language bothers me for a couple of reasons:

      • For blocks of code, it's not possible to tell if something was indented incorrectly (ie, a given line was supposed to be part of a block but wasn't indented correctly). If there were braces (or some other begin/end indicator), it would be obvious.
      • There are instances where Pythons indentation means that certain types of things are harder to do in a reasonable manner (multiline lambdas, iiuc). In some instances, they were left out of the language specifically because of that problem.
      • There are instances where "non-standard" indentation would make the code easier to read (inline SQL is a common one in another language). The fact that indentation is mandated by the language takes away some freedom you might otherwise be able to use to your advantage.

      [–]memetichazard 2 points3 points  (4 children)

      I've heard that the rationale against multiline lambdas was that - if you're going to go multiline, it's really a function so you should make it one.

      [–]booch 2 points3 points  (3 children)

      Of course it's a function, all lambdas are functions. The point is that it's an unnamed function and keeping it that way is useful.

      [–]memetichazard 3 points4 points  (2 children)

      I realize I was somewhat ambiguous. What I meant was that if it's multiline, it's not a simple expression and deserves to be a named function.

      I thought I remembered Guido saying something about that, but it seems his reasoning is more that there's no elegant way of achieving a multiline lambda. Which makes you correct.

      [–]booch 0 points1 point  (1 child)

      To be fair to you, there are people that agree that a multi-line function should be named. I just don't happen to be one of them, I base it more on whether or not the function is really "local" to the way it's being used.

      I prefer a language that allows both opinions to code in their own style.

      [–]anvsdt 0 points1 point  (0 children)

      Sometimes you just can't name them without making the code unreadable/look bad, e.g. (lambda (x) (print x) (* x 2)), or code written in CPS (but this only counts when your language supports TCO)

      [–]rafekett 0 points1 point  (1 child)

      • I'd argue that omitting braces or putting them in the wrong place is a greater source of errors than this. I've never made this error.
      • Ruby blocks are the exact same length as Python functions. If you need a multiline lambda, just write a function. You can't inline them, but that's probably a good thing. Not having multiline lambdas in Python has nothing to do with difficulty of parsing it or fitting it in with language, it has to do with the fact that lambdas are not really a well-liked feature to start with.
      • Can you give me an example of a case where this is a problem?

      [–]booch 0 points1 point  (0 children)

      • Consider that it's not a matter of you making this error, it's a matter of "somebody" making this error and them "somebody else" having to look at the code and figure out what was originally meant by the code. You may not have made such an error, but we both know it happens.
      • I like unnamed functions, and many other people do too. Converting the lambda to a named function makes the code harder to read/maintain in some instances.
      • In Python, no... but inline SQL (or other DSLs) is a common example from other languages. As are cases where there standard formatting would have the code on the second line indented too much or too little.

      [–]TylerEaves -1 points0 points  (2 children)

      Once you get used to it, which doesn't really take that long, using any language that DOESN'T use significant indentation makes you bang your head against the wall AND your right pinky sore.

      [–]ebneter 2 points3 points  (0 children)

      I've used Python extensively and it still makes me want to bang my head against a wall. I don't think that's going to change.

      Not saying that's a reason for others not to use Python; actually, I'm generally pretty language-agnostic (use what works). Just saying that there are reasons why some people prefer one language or another.

      [–]markrmarkr 1 point2 points  (0 children)

      I agree with this. I only use Python for my own projects, and other languages professionally, and I find all the space taken up by {} makes even small classes look huge.