Saturday, February 13, 2016

Ruby Scope

Ruby has perhaps a new variation on the bad old LISP thing of some functions evaluating in the context where they're called rather than in a self-contained scope.

class Foo
  def initialize(a)
    @a = a
  end

  def do_wat(m)
    wat_helper(m)
  end
end

def wat_helper(n)
  @n = n
  @a = "lol"
end

f = Foo.new(1)
p f  #
f.do_wat(2)
p f  #


wat_helper() isn't a member function of any class, so where do its member variables @n and @a bind? Whatever instance context it's called from, apparently.

This is powerful and terrible. On the one hand I could write some nice utility functions for maintaining a tree or a doubly-linked-list and inside any instance maintain @prev, @next, @less, @greater, @parent, and so on. That's great for re-use of the data structure utility functions.
But it's also terrible because I now kinda need to not trust any function I call because it might clobber or pollute my instance variables. There's a notion out there that one should code-review any open source project you're thinking about importing to see if its code is up to your standards. Practically things tend to get in on reputation and basic demonstration of working right. But if code I'm importing can potentially clobber my data structures in this weird way I feel like I should be extra suspicious of it.
https://bolson.org/~bolson/2016/wat_scope.rb

Friday, February 5, 2016

More Rails WAT

If something appears to be in English plural form, Rails will treat it differently. I have more or less come to peace with the Go convention of Capitalized Fields And Methods being 'public' and lower case fields and methods being 'package' scope (in Java/C++ terms). It's weird, but okay I guess. It's a hard and enforced rule, which is probably better than the Python convention of methods and fields starting with '_' being visible but please don't use them please treat them as package or private and not for you.

In my config/routes.rb I wound up with two lines via various experiments in building a rails app:

  resource :event
  resources :event_wats


I wrote a migration by hand which does `create_table :event ...` and I called the setup tool `rails generate scaffold EventWat ...` to create a second table with a migration `create_table :event_wats ...`. I read about this utility in a new tutorial I was reading today and wondered what all I would get from that automated setup. It writes a lot of files!

I also discovered that 'resource' vs 'resources' is a thing. A 'resource' is apparently some kind of singleton. I guess there would only ever be one row of it in the database table. 'resources' get the rest of the REST path bits to deal with multiple rows in the table, list an index of things, etc.

The "Convention over Configuration" doctrine necesitates tools like this! It's like the canonical form of certain special C++ functions, only times twenty. A table of a certain name needs route, model, controller, and view files and classes of certain names.

Rails pedagogy seems to be heavy on tutorial and light on reference documentation. I tried to build my 'event' table based on reference documentation and I missed that the tools had moved on and using `rails generate scaffold` was the new right way to set up things. The reference documentation for setting up a table missed talking about how it ties into the rest of the documentation, and whether the table name should be plural or not and where plural naming matters.

"Convention over Configuration" makes me mad. If I `rails generate scaffold` I get a full set of files that hang together by convention. If I piece things together manually I’ll probably guess the convention wrong at some point and I can’t configure things to hang together because there is no configuration. I just need to rename my classes or tables or files or something until I meet the strange demands of the evil wizard who designed this ‘convention’.

CoC makes the learning curve steeper. It's like I can't just learn one part of the system, I have to learn the whole system at once and the convention it lives by. CoC hides what is going on, and that is not good. I want to have all the moving parts visible and traceable by inspection of the code in a project. I don't want spooky action at a distance. I don't want things to work magically. If something is going to be made easier, I want the APIs designed to make explicit configuration as easy as possible.

Monday, February 1, 2016

Ruby

Here's a line of Ruby from the Rails library:

result = execute schema_creation.accept td

'td' is a variable in local scope
'schema_creation' is a function on the current object, '.accept' is a function on that object, we're passing 'td' to '.accept'
'execute' is a function on the current object, we're passing the result of 'schema_creation.accept td' to 'execute'

I would prefer to write that, for clarity:

execute(schema_creation().accept(td))

Python would insist on the explicit current-object reference:

self.execute(self.schema_creation().accept(td))

But I'm fine with implicit-this of C++ or Java style.

In the Ruby as written (found in Rails/ActiveRecord source) I look at that line of code and think, "What are these words?" There are no hints! I need a Ruby IDE that has evaluated my codebase and looks at the context in any code block to tell me what the things in it are. This is even worse than large Python codebases I'm used to where I have to dig through several files of call chain to figure out what type a parameter being passed in is. Here I don't even know which words are methods or functions or data.