I noticed the evaluation (variableName == null) or (variableName != null) works most of the time.
Apparently the form (null variableName) or (!null variableName) is the proper means and works all the time.
[A] Where is this discussed in the DXL help file (version 8.2)?, and
[B] What is the technical difference?
I'm thinking maybe the (variableName == null) only works for fundamental types and (null variableName) is mandatory when variableName is a reference to an allocated object in memory (e.g., something that required a new() or malloc() in other languages.)
Technical explanation anyone?
SystemAdmin - Thu Mar 11 19:15:57 EST 2010 |
|
Re: (null variableName) vs. (variableName == null) Mathias Mamsch - Fri Mar 12 06:23:14 EST 2010
Now, that is going to be a long answer. The first thing you have to know that null is a function, not a value. The following "null" perms are defined in DOORS, that return NULL values.
_m null ()
string null ()
real null ()
IconID null ()
In addition there are null functions that check for null values:
bool null (string)
bool null (_n)
bool null (real)
Why are there only three null functions? There are different null values in DOORS for different data types. Lets see that by coding:
int a = null
string b = null
real c = null
Object d = null
bool e = null
int ref
ref = (addr_ a) int; print "Int null value: " ref "\n"
ref = (addr_ b) int; print "string null value: " ref "\n"
ref = (addr_ c) int; print "real null value: " ref "\n"
ref = (addr_ d) int; print "Object null value: " ref "\n"
ref = (addr_ e) int; print "Object null value: " ref "\n\n"
print "Int null value = 0 :" (a == 0)" " (a == null) "\n"
print "string null value = \"\" :" (b == "") " " (b == null) "\n"
print "real null value = 0.0 :" (c == 0.0) " " (c == null) "\n"
print "Object null value = 0 :" (addr_ d == 0) " " (d == null) "\n"
print "Bool null value = false:" (e == false) " " (e == null) "\n"
As you can see for this code, most of the time the NULL value is represented by 0, except for strings (which would be a string pointing to an invalid memory location or real where the value 0 represents a very different floating point number. So you can see, that (null string) and (null real) obviously are a reference to an empty string / to a 0.0 real number. As you can see "== null" works for all datatypes, even if you substitute null by the corresponding null value (like 0.0 for reals or false for booleans) it works.
Now it gets ugly. Why do people get errors with the == null expression? The answer is, that DOORS is not perfect in resolving the correct type for variables. Take this code:
real func() { return null }
real var = func();
print (int (addr_ var)) "\n" // prints 0
// this will crash doors since var is no reference to a real but a NULL memory pointer
// print (var == 0.0) "\n"
It prints 0 which is obviously the wrong null value! What happened?
Well Telelogic obviously got tired of declaring null functions for all the 10000 datatypes they defined in DXL. So they introduced the "poison perm" as I like to call it _m null(). The problem with this perm is that it will be used for all other datatypes except real and string (like Module, Skip, etc.). So in some cases, where the "null" is ambiguous DOORS might call the wrong null function.
Now lets fix this example:
real realfunc() { return null real}
real r = realfunc()
print "Should be not 0:" ((addr_ r) int) "\n"
print "Does this work now: " (r == 0.0) "\n"
The same problem happens when you do (if (xyz == null)). If you are out of luck, DOORS will call the wrong null function because it does not resolve the correct null function for the return type. But if you use null (var) then it will work because DOORS perfectly resolves the right null function by the parameter type.
So what is the solution? If you use a "null()" function always cast to the correct type. Dont use "return null".
Hope that clears matters up.
Regards, Mathias
|
|
Re: (null variableName) vs. (variableName == null) SystemAdmin - Fri Mar 12 13:55:52 EST 2010
Wow! Thanks for taking the time to explain the topic so well.
Summarizing, I am coming away with two main lessons.
[A] null() is an overloaded function. Passing in a (typed) variable will aid in DOORS finding the right null() function to call for the evaluation.
[B] If you desire to pass a null value (without realizing a variable of that type) use null but cast it to the desired type. For example
return (Buffer null);
Here is an illustration. This answers my question. If I'm coming away with any wrong idea, do correct. Thanks again.
This code yields the output that follows (DOORS 8.2):
Buffer someBufferFunction() {
// ... some code
// if you are not returning a variable of
// type Buffer do this:
return (Buffer null);
}
Buffer myBuffer;
myBuffer = someBufferFunction();
if (null(myBuffer)) print "EXPERIMENT1: myBuffer is null\n";
if (!null(myBuffer)) print "EXPERIMENT1: myBuffer is not null\n";
delete(myBuffer);
myBuffer = create();
// Results are more reliable to do this:
if (null(myBuffer)) print "EXPERIMENT2: myBuffer is null\n";
if (!null(myBuffer)) print "EXPERIMENT2: myBuffer is not null\n";
// Results are less reliable (and may even crash) to do this:
if (myBuffer == null) print "EXPERIMENT3: myBuffer is null\n"; // -R-E- DXL: <Line:44> null buffer parameter was passed into argument position 2
if (myBuffer != null) print "EXPERIMENT3: myBuffer is not null\n";
delete(myBuffer);
Output:
EXPERIMENT1: myBuffer is null
EXPERIMENT2: myBuffer is not null
-R-E- DXL: <Line:44> null buffer parameter was passed into argument position 2
-I- DXL: execution halted
|
|
Re: (null variableName) vs. (variableName == null) Mathias Mamsch - Fri Mar 12 15:01:53 EST 2010 SystemAdmin - Fri Mar 12 13:55:52 EST 2010
Wow! Thanks for taking the time to explain the topic so well.
Summarizing, I am coming away with two main lessons.
[A] null() is an overloaded function. Passing in a (typed) variable will aid in DOORS finding the right null() function to call for the evaluation.
[B] If you desire to pass a null value (without realizing a variable of that type) use null but cast it to the desired type. For example
return (Buffer null);
Here is an illustration. This answers my question. If I'm coming away with any wrong idea, do correct. Thanks again.
This code yields the output that follows (DOORS 8.2):
Buffer someBufferFunction() {
// ... some code
// if you are not returning a variable of
// type Buffer do this:
return (Buffer null);
}
Buffer myBuffer;
myBuffer = someBufferFunction();
if (null(myBuffer)) print "EXPERIMENT1: myBuffer is null\n";
if (!null(myBuffer)) print "EXPERIMENT1: myBuffer is not null\n";
delete(myBuffer);
myBuffer = create();
// Results are more reliable to do this:
if (null(myBuffer)) print "EXPERIMENT2: myBuffer is null\n";
if (!null(myBuffer)) print "EXPERIMENT2: myBuffer is not null\n";
// Results are less reliable (and may even crash) to do this:
if (myBuffer == null) print "EXPERIMENT3: myBuffer is null\n"; // -R-E- DXL: <Line:44> null buffer parameter was passed into argument position 2
if (myBuffer != null) print "EXPERIMENT3: myBuffer is not null\n";
delete(myBuffer);
Output:
EXPERIMENT1: myBuffer is null
EXPERIMENT2: myBuffer is not null
-R-E- DXL: <Line:44> null buffer parameter was passed into argument position 2
-I- DXL: execution halted
Heh, the example you posted yields the DXL error for another reason. There is another oddity to know about:
The comparison operator. If you do a comparison using "==" in DOORS you are calling one of the following functions:
bool ::== (_xx , _xx)
bool ::== (int , int)
bool ::== (bool , bool)
bool ::== (char , char)
bool ::== (string, string)
bool ::== (Date , Date)
bool ::== (real , real)
bool ::== (Buffer, Buffer)
bool ::== (ModuleVersion, ModuleVersion)
In your case you are calling the ::=(Buffer, Buffer). This function is thought for comparing the contents of a buffer. That is why this function contains a check if you passed a null Buffer and yields an error if you pass a null value. It is probably the same for some other of the above types. So in this case you cannot use the (bufferVar == null) construct, since it will always try to compare the contents and give you the error.
Regards, Mathias
|
|
Re: (null variableName) vs. (variableName == null) SystemAdmin - Fri Mar 12 16:20:28 EST 2010
Thanks. In some days we learn many things. These lessons are similar to C programming. Except in C programming the concepts and operations are explained in books and in DOORS we can only learn by failing and relying on forums like this one.
In C, we use binary operator == to compare fundamental types and we use routines like strcmp() to compare the content of two arrays of characters.
For DOORS, to be successful without falling on your face a few times, one needs to know about topics you discussed (like overloading the == operator and what types the overloads are available for.)
Is there any varsity level documentation beyond the DXL help file and this forum?
PS -- What is '_m' and '_n' ? (I also saw 'addr_' which seems to return the address of the argument.)
|
|
Re: (null variableName) vs. (variableName == null) Mathias Mamsch - Fri Mar 12 18:13:22 EST 2010 SystemAdmin - Fri Mar 12 16:20:28 EST 2010
Thanks. In some days we learn many things. These lessons are similar to C programming. Except in C programming the concepts and operations are explained in books and in DOORS we can only learn by failing and relying on forums like this one.
In C, we use binary operator == to compare fundamental types and we use routines like strcmp() to compare the content of two arrays of characters.
For DOORS, to be successful without falling on your face a few times, one needs to know about topics you discussed (like overloading the == operator and what types the overloads are available for.)
Is there any varsity level documentation beyond the DXL help file and this forum?
PS -- What is '_m' and '_n' ? (I also saw 'addr_' which seems to return the address of the argument.)
Let's face it: DOORS DXL is a big load of crp. Even worse it is not consistent in its structure. And worst: it is not even documented well. Most of the times you get no support when you ask Telelogic/IBM. Bugs are not corrected or redefined as features. Having said that and coming back to DXL:
If you are interested in the DOORS internals you should take a look at the undocumented DOORS perms list (find it for example on smartdxl.com). If you really take a close look at it, you will find it tells you a LOT about how DOORS works internally. It will tell you the undocumented types that enable the DOORS syntax and will tell you why sometimes it works, sometimes it doesnt. The rest is trial and error. I am thinking about writing it all down some time :-)
The _x datatypes. DOORS seems to have something like polymorph types. Did you notice you can put any datatype in a skip list? This is only possible in DXL because Telelogic inserted some special types. They all start with an underscore and match any data type, i.e. if you have a function that takes a _y type parameter it will match any type you give to it. You cannot use them very much in DXL since they almost always make DOORS crash but there are some internal functions that use them, like the put(Skip, _x,y,bool) function that takes any data type and the addr function. The addr_ function does NOT give you the memory address of a variable, it is more like a type cast. You can use it to convert any type to any other type and is very handy if you define your own data types (which is not possible according to the DXL manual, but it is).
Regards, Mathias
The addr_ (_x)
|
|
Re: (null variableName) vs. (variableName == null) Regiss - Sun Jun 13 15:08:56 EDT 2010 Mathias Mamsch - Fri Mar 12 18:13:22 EST 2010
Let's face it: DOORS DXL is a big load of crp. Even worse it is not consistent in its structure. And worst: it is not even documented well. Most of the times you get no support when you ask Telelogic/IBM. Bugs are not corrected or redefined as features. Having said that and coming back to DXL:
If you are interested in the DOORS internals you should take a look at the undocumented DOORS perms list (find it for example on smartdxl.com). If you really take a close look at it, you will find it tells you a LOT about how DOORS works internally. It will tell you the undocumented types that enable the DOORS syntax and will tell you why sometimes it works, sometimes it doesnt. The rest is trial and error. I am thinking about writing it all down some time :-)
The _x datatypes. DOORS seems to have something like polymorph types. Did you notice you can put any datatype in a skip list? This is only possible in DXL because Telelogic inserted some special types. They all start with an underscore and match any data type, i.e. if you have a function that takes a _y type parameter it will match any type you give to it. You cannot use them very much in DXL since they almost always make DOORS crash but there are some internal functions that use them, like the put(Skip, _x,y,bool) function that takes any data type and the addr function. The addr_ function does NOT give you the memory address of a variable, it is more like a type cast. You can use it to convert any type to any other type and is very handy if you define your own data types (which is not possible according to the DXL manual, but it is).
Regards, Mathias
The addr_ (_x)
Regarding: "You can use it to convert any type to any other type and is very handy if you define your own data types (which is not possible according to the DXL manual, but it is). "
Is it possible to define your own data type and have a function to be called depending on the type ?
For example we have three types of list-like structures, a simple list, deque and a double linked list with hash array to speed up the search. But currently they are all represented by the DxlObject type, so either I include some field to distinguish the type into the list structure, or create functions with different names to handle list operations for different types. And definetely in the code I have too many DxlObjects that try to raise null pointer exceptions whenever I forget which does what.
It would be great to have just one name for each fucntion, e.g listLen, and have it defined for three diffrent types:
int lenght (SimpleList lst)
int length (Deque q)
int length (HashList lst).
So if you could reveal a glimpse of the secret: how to define your own data types in dxl you'd be my hero of the day.
I just started "my adventure" with dxl, but either I am lame at googling or it is not such a common knowledge.
|
|
Re: (null variableName) vs. (variableName == null) Mathias Mamsch - Sun Jun 13 16:53:18 EDT 2010 Regiss - Sun Jun 13 15:08:56 EDT 2010
Regarding: "You can use it to convert any type to any other type and is very handy if you define your own data types (which is not possible according to the DXL manual, but it is). "
Is it possible to define your own data type and have a function to be called depending on the type ?
For example we have three types of list-like structures, a simple list, deque and a double linked list with hash array to speed up the search. But currently they are all represented by the DxlObject type, so either I include some field to distinguish the type into the list structure, or create functions with different names to handle list operations for different types. And definetely in the code I have too many DxlObjects that try to raise null pointer exceptions whenever I forget which does what.
It would be great to have just one name for each fucntion, e.g listLen, and have it defined for three diffrent types:
int lenght (SimpleList lst)
int length (Deque q)
int length (HashList lst).
So if you could reveal a glimpse of the secret: how to define your own data types in dxl you'd be my hero of the day.
I just started "my adventure" with dxl, but either I am lame at googling or it is not such a common knowledge.
It is actually very simple and not a big secret. You use the addr_ function to cast your custom type to an existing internal type. I usually use DxlObject but you can also use Array or Skip, whatever internal type fits your class best.
struct myType {}
DxlObject DxlObjectOf (myType T) { return (addr_ T) DxlObject }
string getStringProperty (myType T) { return ((DxlObjectOf T)->"stprop") string }
void setStringProperty (myType T,string s) { (DxlObjectOf T)->"stprop" = s }
myType create_myType () {
DxlObject x = new()
myType mt = (addr_ x) myType
setStringProperty (mt, "Initial Value")
return mt
}
void delete_myType (myType &T) { DxlObject dx = DxlObjectOf T; delete dx; T = null }
myType var = create_myType()
print (getStringProperty var) "\n"
setStringProperty (var, "New Value")
print (getStringProperty var) "\n"
delete_myType var
This approach gets very nice when you override the operators for your own datatype, like:
string ::[] (myType var, int x) { ... implement your own array type ... }
You may start worshipping now :-) Or better, if you implement a list, a deque, etc. datatype, you might want to commit your code to the DXL standard library (a project I founded on sourceforge).
Regards, Mathias
Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS
|
|
Re: (null variableName) vs. (variableName == null) Regiss - Mon Jun 14 03:13:31 EDT 2010 Mathias Mamsch - Sun Jun 13 16:53:18 EDT 2010
It is actually very simple and not a big secret. You use the addr_ function to cast your custom type to an existing internal type. I usually use DxlObject but you can also use Array or Skip, whatever internal type fits your class best.
struct myType {}
DxlObject DxlObjectOf (myType T) { return (addr_ T) DxlObject }
string getStringProperty (myType T) { return ((DxlObjectOf T)->"stprop") string }
void setStringProperty (myType T,string s) { (DxlObjectOf T)->"stprop" = s }
myType create_myType () {
DxlObject x = new()
myType mt = (addr_ x) myType
setStringProperty (mt, "Initial Value")
return mt
}
void delete_myType (myType &T) { DxlObject dx = DxlObjectOf T; delete dx; T = null }
myType var = create_myType()
print (getStringProperty var) "\n"
setStringProperty (var, "New Value")
print (getStringProperty var) "\n"
delete_myType var
This approach gets very nice when you override the operators for your own datatype, like:
string ::[] (myType var, int x) { ... implement your own array type ... }
You may start worshipping now :-) Or better, if you implement a list, a deque, etc. datatype, you might want to commit your code to the DXL standard library (a project I founded on sourceforge).
Regards, Mathias
Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS
Great! Thanks a lot, and if I commit something worth showing, then definitely I'll share the source. I think the hashed list could be interesting if it comes out stable and memory efficient. Currently for my purposes I "implemented" Phong's linear congruential hash, with the name longer than implementation.
BTW, I was forced to inverse bits of the hash result to achieve positive value. But this way I get only 16bits range of numbers, where another 16bits get wasted for not used negative values. It still distributes the elements quite evenly so for now I don't tinker with it, but a native unsigned integer would be nice. Any clues ?
|
|
Re: (null variableName) vs. (variableName == null) SystemAdmin - Thu Jun 17 19:08:39 EDT 2010 Regiss - Mon Jun 14 03:13:31 EDT 2010
Great! Thanks a lot, and if I commit something worth showing, then definitely I'll share the source. I think the hashed list could be interesting if it comes out stable and memory efficient. Currently for my purposes I "implemented" Phong's linear congruential hash, with the name longer than implementation.
BTW, I was forced to inverse bits of the hash result to achieve positive value. But this way I get only 16bits range of numbers, where another 16bits get wasted for not used negative values. It still distributes the elements quite evenly so for now I don't tinker with it, but a native unsigned integer would be nice. Any clues ?
Mathias Mamsch:
Use of the struct / DxlObjectOf combo can certainly work nicely to encapsulate related code.
I disagree with your assessment "It is actually very simple and not a big secret". It is pretty simple but I don't consider anything with only one hit on Google "not a big secret".
OK, I'll start worshiping now.
I can see what DxlObjectOf apparently does from context but an explanation would be helpful. I've programmed in C for many years. Are there other C-like undocumented features not in recent posts?
1) Is there a means of doing a call to a function with a arbitrary number of parameters like C's printf() function? I know it has to be used carefully and forces analysis at run-time rather than compile time but there are situations where it would be very useful.
2) I've used code like:
void *functionToCall(Skip)
to specify a function argument that means "pointer to a function that returns void and takes one Skip argument".
One can the call functionToCall(actualSkipArgument) with the function to invoke by passing a function address. The function that gets the address then knows exactly what to do with it without any casting or addr_ trickery.
Question: In a similar manner, what would the syntax be to specify (for example) "pointer to a function that returns int and takes one Skip argument"?
In C, the address of function is:
functionName;
and to call the function:
functionName() is used;
so I guess you just use addr_ to stop DXL from calling the function rather than evaluating the address.
Since DXL has that dual means of type casting where one can specify:
(CastType variable) or variable CastType
the syntax for turning C-style specs to DXL can be challenging.
No matter what I tried I could never get the right combination for
// "pointer to a function that returns SomeNonVoidType and takes one SomeType (or more) argument"
SomeNonVoidType functionToCall(SomeType someArg);
Any success here?
|
|
Re: (null variableName) vs. (variableName == null) SystemAdmin - Fri Jun 18 13:04:26 EDT 2010 SystemAdmin - Thu Jun 17 19:08:39 EDT 2010
Mathias Mamsch:
Use of the struct / DxlObjectOf combo can certainly work nicely to encapsulate related code.
I disagree with your assessment "It is actually very simple and not a big secret". It is pretty simple but I don't consider anything with only one hit on Google "not a big secret".
OK, I'll start worshiping now.
I can see what DxlObjectOf apparently does from context but an explanation would be helpful. I've programmed in C for many years. Are there other C-like undocumented features not in recent posts?
1) Is there a means of doing a call to a function with a arbitrary number of parameters like C's printf() function? I know it has to be used carefully and forces analysis at run-time rather than compile time but there are situations where it would be very useful.
2) I've used code like:
void *functionToCall(Skip)
to specify a function argument that means "pointer to a function that returns void and takes one Skip argument".
One can the call functionToCall(actualSkipArgument) with the function to invoke by passing a function address. The function that gets the address then knows exactly what to do with it without any casting or addr_ trickery.
Question: In a similar manner, what would the syntax be to specify (for example) "pointer to a function that returns int and takes one Skip argument"?
In C, the address of function is:
functionName;
and to call the function:
functionName() is used;
so I guess you just use addr_ to stop DXL from calling the function rather than evaluating the address.
Since DXL has that dual means of type casting where one can specify:
(CastType variable) or variable CastType
the syntax for turning C-style specs to DXL can be challenging.
No matter what I tried I could never get the right combination for
// "pointer to a function that returns SomeNonVoidType and takes one SomeType (or more) argument"
SomeNonVoidType functionToCall(SomeType someArg);
Any success here?
Foolish me. Referencing my post from yesterday, I now realize DxlObjectOf() was an arbitrary function name. No wonder I only found one hit on Google. I've known about casts via functions but never knew one could use:
struct MyNewType {};
in the manner shown in your example. It is much better than passing structures around and tracking what it does with and what can be passed with comments. With your technique, the DXL compiler will catch inappropriate types being passed. Good find!
|
|
Re: (null variableName) vs. (variableName == null) SystemAdmin - Fri Jun 18 14:50:12 EDT 2010 SystemAdmin - Fri Jun 18 13:04:26 EDT 2010
Foolish me. Referencing my post from yesterday, I now realize DxlObjectOf() was an arbitrary function name. No wonder I only found one hit on Google. I've known about casts via functions but never knew one could use:
struct MyNewType {};
in the manner shown in your example. It is much better than passing structures around and tracking what it does with and what can be passed with comments. With your technique, the DXL compiler will catch inappropriate types being passed. Good find!
// re: DOORS DXL syntax for specifying passing functions to other functions.
Wow, I found something new that answered another one of my questions yesterday, namely passing functions to other functions.
It looks like one can use the general form
void functionToReceiveAnotherFunction(ReturnType anotherFunction(TypeOfParam1, ..., TypeOfParamN));
ReturnType may be anything including void.
The parameter list must have the types of each parameter declared but no parameter names. No parameters at all is an option -- just use "ReturnType anotherFunction()" in the declaration.
In C, "function();" calls a function and use of "function;" (without the "()") will give the address of the function and not call it. In DXL the () is optional. I always wondered what tells DXL whether to call a function or pass the address and I guess it is the context in which used.
I observe the following when a function name is used in another function call:
1) If the signature matches exactly, DXL will pass the address.
2) If the signature does not match, you'll get incorrect arguments for function ( ... )
3) If parameters are supplied, the function will be executed in-line
4) A no-parameter function will work right as a parameter if no () is supplied in the call. If () is supplied, it will compile but DOORS will crash.
string addSomeSuffix(string str) {
return str "-Suffix";
}
string aFunctionWithWrongSignature(string str1, string str2) {
return str1 str2;
}
string aFunctionWithNoParameters() {
return "Hi mom";
}
void printSomeProcessedString(string str,
string f(string)) {
print "str was " str "\n";
print "Now str is " (f(str)) "\n";
}
void printSomething(string f() ) {
print "The passed function returned: " (f) "\n";
}
void functionParameterTest() {
printSomeProcessedString("Base", addSomeSuffix); // works
//printSomeProcessedString("Base", aFunctionWithWrongSignature); //incorrect arguments for function (printSomeProcessedString)
// if address of correctly signatured is stored as int somewhere, the below works also:
printSomeProcessedString("Base", (addr_ (int (addr_ addSomeSuffix))));
printSomething(aFunctionWithNoParameters);
}
int n;
void printN() {
print "n = " (n) "\n"
}
void someFunction(void f()) {
n = 1;
f();
}
void callSomeFunction() {
n = 0;
someFunction( printN ); // address of function passed
n = 0;
someFunction( printN() ); // compiles, does in-line call, DOORS crashes
}
functionParameterTest();
callSomeFunction();
Output is:
str was Base
Now str is Base-Suffix
str was Base
Now str is Base-Suffix
The passed function returned: Hi mom
n = 1
n = 0
|
|