Skip to content

Latest commit

 

History

History
130 lines (109 loc) · 4.2 KB

value.md

File metadata and controls

130 lines (109 loc) · 4.2 KB

VALUE

I want to tell you about VALUE the most basic ruby conception if you take a look on sources it will be present everywhere. Example of C representation of method Enumerable#select:

static VALUE
enum_find_all(VALUE obj)
{
    VALUE ary;

    RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);

    ary = rb_ary_new();
    rb_block_call(obj, id_each, 0, 0, find_all_i, ary);

    return ary;
}

What is about as you can see a we accept magic VALUE obj on input and return VALUE ary on output. Actually VALUE is 32-bit or 64-bit int depend on architecture. Most of the time it acts as pointer but not all of the time. Let me show how actual structure looks like.

VALUE represent basic objects like true,false,nil they treated as constant here example

//ruby.h

enum ruby_special_consts {
#if USE_FLONUM
    RUBY_Qfalse = 0x00,		/* ...0000 0000 */
    RUBY_Qtrue  = 0x14,		/* ...0001 0100 */
    RUBY_Qnil   = 0x08,		/* ...0000 1000 */
    RUBY_Qundef = 0x34,		/* ...0011 0100 */

    RUBY_IMMEDIATE_MASK = 0x07,
    RUBY_FIXNUM_FLAG    = 0x01,	/* ...xxxx xxx1 */
    RUBY_FLONUM_MASK    = 0x03,
    RUBY_FLONUM_FLAG    = 0x02,	/* ...xxxx xx10 */
    RUBY_SYMBOL_FLAG    = 0x0c,	/* ...0000 1100 */
#else
    RUBY_Qfalse = 0,		/* ...0000 0000 */
    RUBY_Qtrue  = 2,		/* ...0000 0010 */
    RUBY_Qnil   = 4,		/* ...0000 0100 */
    RUBY_Qundef = 6,		/* ...0000 0110 */

    RUBY_IMMEDIATE_MASK = 0x03,
    RUBY_FIXNUM_FLAG    = 0x01,	/* ...xxxx xxx1 */
    RUBY_FLONUM_MASK    = 0x00,	/* any values ANDed with FLONUM_MASK cannot be FLONUM_FLAG */
    RUBY_FLONUM_FLAG    = 0x02,
    RUBY_SYMBOL_FLAG    = 0x0e,	/* ...0000 1110 */
#endif
    RUBY_SPECIAL_SHIFT  = 8
};

You can ask what is USE_FLONUM its optimization for working with floating numbers for 64-bit systems introduced long time ago in short for storing float types in VALUE for performance improvements before it was stored as an regular ruby object more information Ok but how ruby detect is VALUE is just a plain int or it's a pointer? Actually by first 3-bits if it's 64-bit architecture or 2-bits if its 32-bit architecture. Here the code that checks which type actually VALUE is

//ruby.h

static inline int
rb_type(VALUE obj)
{
    if (RB_IMMEDIATE_P(obj)) {
	if (RB_FIXNUM_P(obj)) return RUBY_T_FIXNUM;
        if (RB_FLONUM_P(obj)) return RUBY_T_FLOAT;
        if (obj == RUBY_Qtrue)  return RUBY_T_TRUE;
	if (RB_STATIC_SYM_P(obj)) return RUBY_T_SYMBOL;
	if (obj == RUBY_Qundef) return RUBY_T_UNDEF;
    }
    else if (!RB_TEST(obj)) {
	if (obj == RUBY_Qnil)   return RUBY_T_NIL;
	if (obj == RUBY_Qfalse) return RUBY_T_FALSE;
    }
    return RB_BUILTIN_TYPE(obj);
}

After check that VALUE is not special value ruby try to check which type of object VALUE is

//ruby.h
enum ruby_value_type {
    RUBY_T_NONE   = 0x00,

    RUBY_T_OBJECT = 0x01,
    RUBY_T_CLASS  = 0x02,
    RUBY_T_MODULE = 0x03,
    RUBY_T_FLOAT  = 0x04,
    RUBY_T_STRING = 0x05,
    RUBY_T_REGEXP = 0x06,
    RUBY_T_ARRAY  = 0x07,
    RUBY_T_HASH   = 0x08,
    RUBY_T_STRUCT = 0x09,
    RUBY_T_BIGNUM = 0x0a,
    RUBY_T_FILE   = 0x0b,
    RUBY_T_DATA   = 0x0c,
    RUBY_T_MATCH  = 0x0d,
    RUBY_T_COMPLEX  = 0x0e,
    RUBY_T_RATIONAL = 0x0f,

    RUBY_T_NIL    = 0x11,
    RUBY_T_TRUE   = 0x12,
    RUBY_T_FALSE  = 0x13,
    RUBY_T_SYMBOL = 0x14,
    RUBY_T_FIXNUM = 0x15,
    RUBY_T_UNDEF  = 0x16,

    RUBY_T_IMEMO  = 0x1a, /*!< @see imemo_type */
    RUBY_T_NODE   = 0x1b,
    RUBY_T_ICLASS = 0x1c,
    RUBY_T_ZOMBIE = 0x1d,
    RUBY_T_MOVED  = 0x1e,

    RUBY_T_MASK   = 0x1f
};

Which function/macros are available to work with VALUE short list of them

void rb_check_type(VALUE,int); //check value have proper type if not raise exception
int rb_type(VALUE obj); // return obj type
rb_type_p(obj, type); return true if obj match type
char *rb_string_value_ptr(volatile VALUE*); // return pointer to a char sequence from string VALUE
VALUE rb_str_new(const char *ptr, long len); // create ruby string from char*
VALUE rb_sprintf(const char *format, ...); // create ruby string from formated *char
VALUE rb_data_typed_object_wrap(VALUE klass, void *datap, const rb_data_type_t *type); // function wrap user structure to a ruby object