problem-solving icon indicating copy to clipboard operation
problem-solving copied to clipboard

Routines could use more support for reflection

Open Kaiepi opened this issue 6 years ago • 8 comments

My Trait::Traced module implements support for tracing routine calls. There are some problems with the output produced by traced routine calls though:

  • Private methods and metamethods don't get traced accurately because there doesn't seem to be a simple way to determine which type of method a method was declared to be from a trait, since it happens before the method actually gets added to the type.
  • Tokens, rules, and regexes all get traced as being declared to be regexes because there doesn't seem to be a simple way to determine what type of regex declaration they were created with.
  • What type of declaration any type of routines was created with needs to be inferred from its type's name and the is_dispatcher and multi methods of Routine. This isn't entirely reliable since type names can be reset (this may be a case of DIHWIDT though).

Because tracing probably isn't the only scenario where reflection like this would be useful, I think more support for reflecting routines themselves, similarly to how you can reflect their signature, should exist. In Rakudo, this support could be used to optimize the gist and raku methods of the various routine types and make their output more accurate.

Kaiepi avatar Jan 16 '20 20:01 Kaiepi

I propose adding the following methods:

  • Routine.multi_declarator

Returns the multi declarator the routine was declared with (or Nil if there is none).

  • Routine.declarator

Returns the routine declarator the routine was declared with.

  • Method.prefix

Returns '!' for private methods, '^' for metamethods, or Nil for regular methods.

  • Method.private

Returns whether or not the method was declared as a private method.

  • Method.meta

Returns whether or not the method was declared as a metamethod.

Kaiepi avatar Jan 16 '20 21:01 Kaiepi

A couple of thoughts:

  1. Routine objects are already big enough. Not only are we paying the cost of their storage in compiled output, but also every closure clone of a Routine pays for any extra state we add. I guess Routine.multi_declarator can be inferred from existing state, but the others not.
  2. Whether a method is a private or meta-method isn't a property of the method itself, but rather the method table it is installed into. It would be entirely possible (if unusual) for a method to be installed as both a private and a normal method. So I'm not really in favor of these ones.
  3. If we really want to know about regex vs. rule vs. token I'd rather model that with subtypes of Regex instead.

jnthn avatar Jan 16 '20 23:01 jnthn

On 17 Jan 2020, at 00:48, Jonathan Worthington [email protected] wrote:

A couple of thoughts:

• Routine objects are already big enough. Not only are we paying the cost of their storage in compiled output, but also every closure clone of a Routine pays for any extra state we add. I guess Routine.multi_declarator can be inferred from existing state, but the others not.

If Routine objects are basically too fat for their own good, would it make sense to combine $!rw, $!yada and $!onlystar into a single bitmap, thereby reducing each Routine by 128 bytes? Or even more if it would make sense to make that bitmap an int8?

• If we really want to know about regex vs. rule vs. token I'd rather model that with subtypes of Regex instead.

This looks an easy way to do this. Has worked fine for ObjAt and ValueObjAt, and Iterator and PredictiveIterator :-)

lizmat avatar Jan 16 '20 23:01 lizmat

If Routine objects are basically too fat for their own good, would it make sense to combine $!rw, $!yada and $!onlystar into a single bitmap, thereby reducing each Routine by 128 bytes?

Probably $!rw and $!yada you can, and it's worth it. But $!onlystar is, iirc, looked at by the multi cache mechanism inside of the VM, so it's rather harder to eliminate it.

Or even more if it would make sense to make that bitmap an int8?

I suspect alignment means that you'll not gain anything.

jnthn avatar Jan 17 '20 00:01 jnthn

I've merged the $!rw and $!yada attributes into a single $!flags attribute. Added a set_flag and get_flag method, so that additional flag-like meta-information could be added easily. All available and spectest clean in https://github.com/rakudo/rakudo/commit/4366980681.

lizmat avatar Jan 17 '20 09:01 lizmat

Routine.multi_declarator Returns the multi declarator the routine was declared with (or Nil if there is none).

You mean, whether the routine is a multi or not? Isn't that already available in the Routine.multi bool?

Routine.declarator Returns the routine declarator the routine was declared with.

You mean: either sub or method or role or regex etc?

If we really want to know about regex vs. rule vs. token I'd rather model that with subtypes of Regex instead.

It struck me that all dispatch related attributes of Routine are basically unused if the Routine is an only sub or an only method. Would it make sense to move all of those attributes to a subclass of Routine (tentatively called MultiRoutine) and thus save a lot of overhead on the non-multi cases?

lizmat avatar Jan 17 '20 12:01 lizmat

You mean, whether the routine is a multi or not? Isn't that already available in the Routine.multi bool?

I mean if it was declared with proto, multi, or only. multi can be inferred with Routine.multi and proto with Routine.is_dispatcher, but how would you tell if a routine was declared with only or not? $*MULTINESS can be used from traits to determine this, but not in very many other cases.

You mean: either sub or method or role or regex etc?

sub, method, submethod, regex, token, or rule, mainly.

Kaiepi avatar Jan 17 '20 16:01 Kaiepi

An update on this: I'm currently doing some early R&D on macro implementation, which along the way will involve giving us a spec'd DOM for Raku code. I expect that a trait applied to a method shall be able to obtain the node for the method it's being applied to (so long as it's called at compile time, which traits are). It will be able to use that to get hold of whatever it wishes - without us having to preserve any further information to runtime in the general case.

jnthn avatar Feb 20 '20 00:02 jnthn