Hacker News new | ask | show | jobs
by theyeti 3892 days ago
I've somehow always found Ruby to be opposite to the Unix philosophy of doing one thing and doing it well. While Ruby may seem trivial and fun in the beginning, it tends to be cumbersome and maintainable as the size of the repository grows. Coming from a Python world, my first reaction to Ruby was that it was more like Perl where there are many ways to achieve the same thing, and no it was not really helpful if you inherited poorly written code.
1 comments

> opposite to the Unix philosophy

Bash:

  $ foo()
  {
    bar ()
    {
      echo I am bar
    }
  }
  $ bar
  bar: not found
  $ foo
  $ bar
  I am bar
Pretty much the same thing as the Ruby example.

This is simply because function defining is a kind of statement or expression with a side effect which must be evaluated. The side effect is global (a name is globally associated with a function). So if the side effect is in a function body, its evaluation is delayed until the function is called, and then its effect is still global.

If you're a sufficiently advanced Unix purist (aka a Plan 9 user), the Bourne shell is a violation of Unix principles. Contrast the v6 shell, where this construct is impossible because there are no functions. Now that's do-one-thing-do-it-not-quite-terribly.

Does this work in Plan 9 rc?

This is indeed the basic feature of any language that's evaluated at runtime. When working with such a language, one needs to learn the program as a dynamically growing construct instead of a vision cast in stone when you press the "compile" button.
Or rather, one needs to learn which constructs destructively manipulate a global environment, and which perform lexical binding.

In Python, an inner def will lexically bind a function, creating a closure. Python is not less dynamic than Ruby.

In Common Lisp, a defun inside a defun will behave similarly to Ruby; but if you want lexically scoped local functions, you use a different operator, namely flet or labels.

Scheme has a define which is lexical: it brings a lexical identifier into the scope for forms which follow.

Lexically scoped items, even in a dynamic language, in fact can be "cast in stone when you press the compile button"; they are cast in that stone which is the entire compiled environment of the surrounding function.

Touché