Search code examples
rubylambdaintrospectionproc

How can one know if a Proc is a lambda or not in Ruby


Suppose I have created a lambda instance, and I want later to query this object to see if it is a proc or a lambda. How does one do that? the .class() method does not do the trick.

irb(main):001:0> k = lambda{ |x| x.to_i() +1 }
=> #<Proc:0x00002b931948e590@(irb):1>
irb(main):002:0> k.class()
=> Proc

Solution

  • Ruby 1.9.3 and higher

    You are looking for Proc#lambda? method.

    k = lambda { |x| x.to_i + 1 }
    k.lambda? #=> true
    k = proc { |x| x.to_i + 1 }
    k.lambda? #=> false
    

    Pre 1.9.3 solution

    We are going to make ruby native extension. Create proc_lambda/proc_lambda.c file with following content.

    #include <ruby.h>
    #include <node.h>
    #include <env.h>
    
    
    /* defined so at eval.c */
    #define BLOCK_LAMBDA  2
    struct BLOCK {
        NODE *var;
        NODE *body;
        VALUE self;
        struct FRAME frame;
        struct SCOPE *scope;
        VALUE klass;
        NODE *cref;
        int iter;
        int vmode;
        int flags;
        int uniq;
        struct RVarmap *dyna_vars;
        VALUE orig_thread;
        VALUE wrapper;
        VALUE block_obj;
        struct BLOCK *outer;
        struct BLOCK *prev;
    };
    
    /* the way of checking if flag is set I took from proc_invoke function at eval.c */
    VALUE is_lambda(VALUE self) 
    {
        struct BLOCK *data;
        Data_Get_Struct(self, struct BLOCK, data);
        return (data->flags & BLOCK_LAMBDA) ? Qtrue : Qfalse;
    }
    
    void Init_proc_lambda() 
    {
        /* getting Proc class */
        ID proc_id = rb_intern("Proc");
        VALUE proc = rb_const_get(rb_cObject, proc_id);
    
        /* extending Proc with lambda? method */
        rb_define_method(proc, "lambda?", is_lambda, 0);
    }
    

    Create proc_lambda/extconf.rb file:

    require 'mkmf'
    create_makefile('proc_lambda')
    

    In terminal cd to proc_lambda and run

    $ ruby extconf.rb
    $ make && make install
    

    Test it in irb

    irb(main):001:0> require 'proc_lambda'
    => true
    irb(main):002:0> lambda {}.lambda?
    => true
    irb(main):003:0> Proc.new {}.lambda?
    => false