‘e’ language is an Aspect Oriented Programming (AOP) language with a lot of awesome features. One of this features is the ability to extend methods with one of the following statements:
- is also
- is first
- is only
In this article we’ll see the strange way in which Specman’s return statement behaves with this very nice method extension feature of ‘e’.
In ‘e’ language, you can define a method very easily in this manner:
extend sys { acme_print() is { message(NONE, "From \"is\" declaration"); }; };
One cool way in which we can append some lines of code to acme_print() method is to extend it using is also statement:
extend sys { acme_print() is also { message(NONE, "From \"is also\" declaration"); }; };
At this point, calling acme_print() method will produce an output like this one:
[0] sys-@1: From "is" declaration [0] sys-@1: From "is also" declaration
In the same manner we can prepend some lines of code to acme_print(), but this time using is first statement:
extend sys { acme_print() is first { message(NONE, "From \"is first\" declaration"); }; };
Calling acme_print() method now will produce an output like this one:
[0] sys-@1: From "is first" declaration [0] sys-@1: From "is" declaration [0] sys-@1: From "is also" declaration
So it seams that all these method extensions are equivalent to writing the function like this:
extend sys { acme_print() is { message(NONE, "From \"is first\" declaration"); message(NONE, "From \"is\" declaration"); message(NONE, "From \"is also\" declaration"); }; };
Pretty straight-forward, right? However, things get a bit strange when we extend value returning methods.
Let’s see a simple example in action:
extend sys { get_value() : uint is { return 2; }; get_value() : uint is first { return 1; }; get_value() : uint is also { return 3; }; run() is also { messagef(NONE, "Returned value is: %d", get_value()); }; };
If we follow the same logic path as for acme_print() method, we would expect to get value 1 when we call get_value() method as the above code would be equivalent with this one:
extend sys { get_value() : uint is { return 1; return 2; return 3; }; };
However when we run this code, Specman does not agree with our expectation and prints 3:
[0] sys-@1: Returned value is: 3
You can give it a try on your own if you don’t believe me on EDA Playground.
So it looks like that Specman actually runs all extensions of get_value() and returns the value specified by the last return statement. We can test this theory very easily by removing the is also extension from our code:
extend sys { get_value() : uint is { return 2; }; get_value() : uint is first { return 1; }; run() is also { messagef(NONE, "Returned value is: %d", get_value()); }; };
This should be equivalent to writing get_value() in this way:
extend sys { get_value() : uint is { return 1; return 2; }; };
So based on the previous experiment, when Specman returned the value specified by the last return statement, it is fair to assume that this time the return value is 2.
If you where expecting to see value 2 printed you would be wrong because Specman decides in this scenario to print value 1:
[0] sys-@1: Returned value is: 1
Try it on EDA Playground because I can’t believe this thing either.
As expected, it turns out that this behavior is described in ‘e’ language reference manual. The actual rules that govern this behavior are the following:
- A method extension using is also will always be called, even if the previous version of the method called return statement.
- If a method extension using is first calls return statement then the previous version of the method will not be executed.
Food for thought: what do you think is the behavior if you use result variable instead of return? Will the value from is first be visible in is? Or will the value from is be visible in is also?
Make sure you check out the ‘e’ Language Reference Manual as this provides all the answers when it comes to this awesome programming language.
Give it a try on your own quickly and easily on EDA Playground.
This gets weirder.
if you put the ‘is first’ in another extend of the struct, it will only do the is first (work as expected).
if you then add an ‘is also’ in another extended struct, it will also do the ‘is also’, but only from the other struct!