Untyped Values and Value Holders
The reflection API in e not only allows you to perform static queries about your code, but it also allows you to perform dynamic operations on your environment at run time. For instance, you can use reflection to examine or modify the value of a field, or even invoke a method, in a generic way. This means that if the specific field or method name is unknown a priori, but you have the reflection representation of the field or the method at hand, the reflection API provides you with the capability to perform the needed operation.
While this is a very strong and helpful capability, it should be used with care, to avoid unexpected results or even crashes. In this series of blogs, I will describe how to use some of these capabilities, as well as some tricky points which require caution in use.
In this first blog of the series, let's look at two important concepts with which you should be familiar: untyped values and value holders.
Untyped is a predefined pseudo-type in e, serving as a place-holder for any value of any type, which may be a scalar, a struct, a list, or any other valid e type. To assign a value to a variable of type untyped, you use the predefined pseudo-method unsafe(). For example (assuming my_packet is a struct field of type packet):
var a1: untyped = 5.unsafe();
var a2: untyped = my_packet.unsafe();
In this example, we assigned the numeric value 5 into untyped variable a1, and the struct value into untyped variable a2. We also use unsafe() to assign an untyped value back to a variable or a field of the original type, for example:
my_packet = a2.unsafe();
However, it is important to remember that the untyped variable itself does not know the actual type of the value assigned to it via unsafe(). Therefore, when you convert a value to untyped, it is your responsibility to later convert it to the correct original type. Thus, you need to avoid mistakes like this:
my_packet = a1.unsafe(); // This is bad code!
Here we take the value of the untyped variable a1 and try to assign it to my_packet. However, the value assigned previously to a1 was a scalar, not an instance of packet. So, this operation is illegal. The code would compile fine, but at run time it would most likely crash.
In simple cases, to avoid such mistakes you just need to be careful. In more complex cases, you can use a value holder. A value holder is a special object in e, of the pre-defined type rf_value_holder, and it allows you to keep a value of any given type along with its type information. So, as opposed to untyped, here the original type of the value is known. There are several reflection methods that operate on value holders. To create a value holder, we use the create_holder() method of rf_type, for example:
var vh1: rf_value_holder = rf_manager.get_type_by_name("int").create_holder(5.unsafe());
Here we created a value holder that keeps that value 5 of the type int. Note that since the create_holder() method itself can get a value of any type, it treats it as untyped; that's why we had to use unsafe() here. But as long as you call it on the correct rf_type (in this case, the one that represent the int type), it is fine.
Later we can enquire the type of the value kept in the holder, using the get_type() method:
print vh1.get_type();
or the actual value, using the get_value() method:
var x: int;
if vh1.get_type() == rf_manager.get_type_by_name("int") then {
x = vh1.get_value().unsafe();
};
An important tip:
In general, conversions from any type to untyped and vice versa must only be done using unsafe(). It is a common mistake to use the explicit casting operator as_a(). Doing so leads to unexpected results (and consequently to confusions) and must be avoided. For example, the following causes an unexpected result.
var x: int(bits: 64) = 5;
var a: untyped = x.unsafe();
x = a.as_a(int(bits: 64));
In upcoming Specman releases (starting 13.2), using as_a() with untyped is going to be completely disallowed through a deprecation process.
In the next blog of this series we will look at some actual dynamic usages of the reflection API, based on untyped values and value holders, as well as some helpful tips.
Yuri Tsoglin
e Language team, Specman R&D