Archive for January, 2012

Mirah Office Hours: Digging In

Wednesday, January 18th, 2012

Mirah -v Frankly embarrassing

This week I wanted to deal with one embarrassing bug, and some that looked fun. After looking through everything last week, I felt like I got a better sense about the current issues. So, I picked a few issues to work on that I thought I could dig into and get something working in an afternoon. I think I was a little ambitious.

First I wanted to fix #161 mirah -v causing an error because, frankly it’s embarrassing. I also thought it’d be pretty easy. It was, but the fix wasn’t as clean as I’d like.

Next time I’m in the option handling code, I’m going to do some house cleaning–it’s getting a bit ugly. For instance, parser should not take a list of commandline args and have to worry about ‘-e’ etc. How to reorganize it I haven’t decided. Maybe using optparse, though that has its own idiosyncrasies.

#13 booleans don’t have an == method.

I fixed this by adding an intrinsic to the jvm backend code. It’s not especially pretty. The intrinsics code is tied up in a few files and some of them feel like balls of mud. It’s not readily apparent where to find things and what they do.

I’ve been thinking about how to make intrinsics nicer and more consistent. It might be nice to have some common types with a common set of expected method definitions that the various (hypothetical) backends should implement. That way you’d have some consistency across different Mirah backends.

I’d also like to reorganize the intrinsics and make their internal APIs easier to grok. Things I’d like to do with them, like allowing easy method aliasing are hard right now, because the API has a lot of sharp edge cases.

Test cleanup

After fixing #13, I renamed all the test files. I was getting frustrated w/ having them all be prefixed with test_. That made tabbing into the right test file take a couple more keystrokes. It added just enough friction that I wanted to change it. So I did.

#30 Const Assign

This one is definitely not a single Sunday afternoon project. And, honestly I didn’t expect it to be. I spent about an hour trying to figure out what would need to change to support creating constants. It looks kind of annoying.

First, you need to transform the mmeta AST nodes into a Mirah AST node for the Const Assign, which could be as simple as creating a static FieldAssign. Then you need to change the code generation to deal with that. Unfortunately, FieldAssign’s don’t currently know about access levels (public, private, protected) which means you’d either have to add access levels to field assign, or create a new AST class that would have to be dealt with in the code generation phase.

Thinking about it a little, it might be nicer to do the second thing. Then, different (hypothetical) backends could handle access levels for constants their own way. That might be handy, particularly if constants are special in different ways in different languages.

#41 i++

The other thing I looked at briefly was adding ++ to the grammar. This turned out to be rather hard looking because the parser’s master branch is tied to mirah’s newast branch, which has a lot of new things in it and doesn’t work with the current release yet.

I’m debating creating a new branch on the parser at a point before it started using the new AST. On the other hand, it might make sense to spend more time trying to update the newast branch so that it is up to date with master. Then I could get it closer to merging back in.

That’s all for this week.

Mirah Office Hours: Back After the Holidays

Tuesday, January 10th, 2012

This week I decided to go and read all of Mirah’s open issues starting with the earliest submitted ones. I’d been spending so much time just looking at the top of the list. I didn’t have a good sense for which ones were duplicates, which were pretty undefined and which were easy. Thankfully, Mirah doesn’t have that many issues, so attempting to read through them all wasn’t a ridiculous undertaking. There were only 64, and I had filed about a half dozen of them myself.

In the end, I was able to close 7, and get a good sense of where a number of the other ones stood in terms of how much work it’ll take to fix them. Of course there were a few that made me confused, where I don’t have any idea where to start digging to fix them.

After going through the stack of issues, I have a better sense of what I want to try to tackle next week. Here’s a few that I think look fun.

#41 – adding ++ to the language.

++ isn’t in the grammar yet, so this would require learning more about the parser. And, I’d get to play around with the grammar, which is always fun, and something I haven’t done much of since graduating.

#127 & #42 – working out the semantics of equality.

Currently Mirah uses Java’s ==, which checks identity not equality. We’d like to use Java’s equals as our ==, but I’ve had a little trouble getting it working properly. Still, this is a fun one to hack on.

#45 – an issue with how field assignments check typing

Namely, they don’t really. It isn’t completely straight forward but I think I’ve nailed down where to make the changes.

#57 – who is self in a block

This looks fun. I’m not quite sure how to make it work. The problem is that you want blocks to work like they do in Ruby, where self is the owner of the outer scope. Currently, Mirah’s bindings don’t do that, so self is the instance of the closure. Looking at this got me thinking about non local return(NLR). There was an interesting discussion about it on Twitter today with @evanphx saying

NLR in closure comment by @evanphx

I think it’d be really interesting to try to add NLR to Mirah’s blocks. It might be crazy, but it could also be awesome.

#69 – Mirah doesn’t check blocks signature against the signature of the method they’re supposed to be implementing.

Madness, but madness I think I can fix.

#74 Constants!

Mirah doesn’t let you create constants, other than classes and interfaces. I’d like to change that. And, the error tells you what’s missing. Now, all I’ve got to do is figure out how to implement it.

Tune in next week…

And that’s what I’m looking at doing next Sunday. Or some of it anyway. There’s a bunch of trickiness out there.

Upgrading from Rails 2.3.8 to 2.3.14: find_or_create_by on associations changed

Monday, January 9th, 2012

Update: I’m not the first one to run into this: lighthouse ticket find_or_create-via-has_many-fails-for-hash-parameters and rails/rails#207.
Between 2.3.8 and 2.3.9 a change was added to ActiveRecord::Associations::AssociationCollection#method_missing that caused find_or_create_by_* to no longer accept hashes as arguments. An app I was upgrading from 2.3.8 ran into this as it passed hashes to a find_or_create_by_* call.

The symptom was that foobar in find_or_create_by_foobar became a serialized hash when saved to the database, instead of the string I was expecting.

The reason it was changed was to ensure that the caches on the collection were updated properly (lighthouse 1108) & (commit fad166c1), which is pretty important, but the fix didn’t take into account dealing w/ two of the cases that find_or_create_by_* accepts when called on an ActiveRecord class:

  • post.comments.find_or_create_by_body :body => 'bar', :type => 'baz'
  • post.comments.find_or_create_by_body 'bar', :type => 'baz'

The new behavior looked like this:

I wrote a patch for it (github.com/rails/rails/pull/4331). Then I found out that 2.3 is only accepting security patches, so I closed it.

If you run into this and you want to use my patch, refer to gist 1586708 which has a monkey patchified version of it. If you want to work around the bug, you can use the optional block to set the attributes you were passing in the hash.

Test ActiveRecord with Reset Transactions Without Rails

Monday, January 9th, 2012

I found myself wanting to use Rails’ test transaction functionality in a Rails-less environment, and couldn’t find a tutorial about it. So I dug into the Rails source to figure out how it worked–just enough to pull it out into a gist. So, if you add this to your test_helper.rb or equivalent, you too can have your ActiveRecord tests wrapped in transactions that rollback after each case. It also lets you use fixtures, but who does that?