Past weeks were quite smooth for me except a few last days, so here is the report:
Accomplishments:
This the list of the issues which I have done till now. Most of them are about writing a structured exception for an error, except some selected or better to say horrible ones :D, which I’ll discuss next.
Major accomplishment:
Working on this inline exception. I took around 4-5 days for this. Here is the log of commits related to this exception.
Why it was tough?
- Reading the generated inline code: Reading and interpreting inline code was a big deal for me, because it had nested if statements, improper indentation etc. Here is a sample of inline code (only first file). Jesse asked me to install Perl::Tidy module, I did and then the code became legible.
- Understanding how inline code is generated: In Moose, inline code is generated through eval blocks, which are generated in sub _eval_environment (it’s generated in other places also, but for this exception it’s generated in Moose::Meta::Attribute::_eval_environment):
sub _eval_environment { my $self = shift; my $env = { }; $env->{'$trigger'} = \($self->trigger) if $self->has_trigger; $env->{'$attr_default'} = \($self->default) if $self->has_default; if ($self->has_type_constraint) { my $tc_obj = $self->type_constraint; $env->{'$type_constraint'} = \( $tc_obj->_compiled_type_constraint ) unless $tc_obj->can_be_inlined; # these two could probably get inlined versions too $env->{'$type_coercion'} = \( $tc_obj->coercion->_compiled_type_coercion ) if $tc_obj->has_coercion; $env->{'$type_message'} = \( $tc_obj->has_message ? $tc_obj->message : $tc_obj->_default_message ); $env = { %$env, %{ $tc_obj->inline_environment } }; } $env->{'$class_name'} = \($self->associated_class->name); # XXX ugh, fix these $env->{'$attr'} = \$self if $self->has_initializer && $self->is_lazy; # pretty sure this is only going to be closed over if you use a custom # error class at this point, but we should still get rid of this # at some point $env->{'$meta'} = \($self->associated_class); return $env; }
In the above code, $env is a HASH reference. We need to initialize key-value pairs of variable names and their values which we want in our inline code. Thank you Jesse for explaining it to me.
-
Making either metaclass object or class name available in the inline code: Using metaclass objects in the inline code leads some problems because of some circular dependencies in Moose. So I was trying to pass class name to the exception, because I can easily get the metaclass object of a class if I know its name.
Long time ago, my mentor, Shawn asked me to work on this issue. At that time, I didn’t totally understand the reason of making that modification to Moose::Exception::Role::Class, but now I have understood why Shawn asked me to do that. Lines 169 to 187 of this gist has the concerned code. - Making existing tests pass: After I made changes in the code, my next task was to make all existing tests pass. Here, I did a mistake, after committing my changes, I didn’t run the test suite, I did it after 1 day (may be because of frustration) :(. I committed a lot of other code in the meantime, so it was hard to tell which commit is the cause of test suite failure. Shawn told me about git bisect, which uses binary search algorithm. It’s a very good tool for debugging (will try to explain in a different post). I used it for getting the commit which was the cause of the test suite failure. Thank you Shawn for telling me about such a good tool.
Next?
I’ll try to finish non-inline exceptions first, because I think my mind can’t cope with sudden transitions from inline to non-inline exceptions and vice-versa :D. After that, I’ll again do horrible inline exceptions 😀