How can I overload the '=' operator in Ada without creating a recursive function? - overloading

FUNCTION "=" (lString1, lString2 : IN lString) RETURN boolean IS
IF lString1 = NULL AND lString2 = NULL THEN
RETURN true;
ELSIF lString1 = NULL OR lString2 = NULL THEN
RETURN false;
END IF;
I'm trying to overload the equality operator in Ada. Each time I use the operator '=' within the function it causes a recursion which leads to a stack overflow, rather than use the ada defined operator which I need. Is there a way to differentiate it from my overloaded operator?

By introducing a non-overloaded utility function to do the access type comparisons, the OP's function definition, with the needed syntax fixes and modified to use the utility function, can be made to work.
I'm still puzzled, though, as to why invoking "=" as Standard."=" is rejected by the compiler (GNAT) for specifying "incompatible arguments".
with Text_IO; use Text_IO;
procedure non_recursive_equals is
type Lstring is access String;
-- Be aware, the ordering of the functions here is important!
function Is_Equal(Lstring1, Lstring2 : in Lstring) return Boolean is
begin
return Lstring1 = Lstring2;
end Is_Equal;
function "=" (lString1, lString2 : in Lstring) return Boolean is
begin
if Is_Equal(LString1, null) and Is_Equal(LString2, null) then
return True;
elsif Is_Equal(LString1, null) or Is_Equal(LString2, null) then
return False;
end if;
return False;
end "=";
L1, L2 : Lstring := null;
begin
Put_Line("L1 and L2 null: " & Boolean'Image(L1 = L2));
L2 := new String(1..10);
Put_Line("L2 not null : " & Boolean'Image(L1 = L2));
end non_recursive_equals;
Edit:
Here's another way, using a renames clause:
with Text_IO; use Text_IO;
procedure non_recursive_equals is
type Lstring is access String;
function Is_Equal (lString1, lString2 : in Lstring) return Boolean is
begin
if lString1 = null and lString2 = null then
return True;
elsif lString1 = null or lString2 = null then
return False;
end if;
return False;
end Is_Equal;
function "=" (Lstring1, Lstring2 : in Lstring) return Boolean renames
Is_Equal;
L1, L2 : Lstring := null;
begin
Put_Line ("L1 and L2 null: " & Boolean'Image (L1 = L2));
L2 := new String (1 .. 10);
Put_Line ("L2 not null : " & Boolean'Image (L1 = L2));
end non_recursive_equals;

Here's yet another way, using only Ada83... and a horrid example/abuse of exceptions:
Type LString is Access String;
Function "=" (Left, Right: IN LString) Return Boolean is
Subtype Constrained_LString is Not Null LString;
Function Is_Equal( Left : LString; Right : String ) Return Boolean is
begin
Return Right = Left.All;
exception
When CONSTRAINT_ERROR => Return False;
end Is_Equal;
Begin
Return Is_Equal(Left, Right.All);
Exception
When CONSTRAINT_ERROR =>
begin
Return Is_Equal(Right,Left.All);
Exception
When CONSTRAINT_ERROR => Return True;
end;
End "=";
What happens is if it is called and Right = Null the attempt to de-reference it causes an exception; in this case we try to de-reference Left and if that too fails then both must be Null.
In the case where only one fails the equality must be false and in the case where both parameters can be de-referenced the result is the test for equality on those strings.

I was able to reproduce the same behavior with similar code. I took the liberty of assuming that lString was some sort of string access type
I believe the recursion is being caused by the fact that your new = function masks the natively provided one. Since they share both the same name, parameters, and return value, there is no straightforward way of distinguishing between the two.
An inelegant way around this would be to avoid overloading entirely and to define a new function with the same behavior as your overloaded function, with a different name such as Is_Equal.

I'm not sure why "=" is being used recursively; possibly, there is an unfortunate use clause present. The example below overloads "=" and produces the following output. The overloaded function implicitly invokes Standard."=" for the comparison. Note you can specify renames to simplify package names, and you can use type to expose just the operators applicable to a type.
Addendum: I've added an alternate way to invoke Standard."=" in a comment below.
Console:
********************
********************
TRUE
TRUE
Code:
with Ada.Strings.Bounded;
with Ada.Strings.Unbounded;
with Ada.Text_IO;
procedure UseType is
package String20 is new Ada.Strings.Bounded.Generic_Bounded_Length(20);
use type String20.Bounded_String;
package StringN renames Ada.Strings.Unbounded;
use type StringN.Unbounded_String;
function "=" (Left : String20.Bounded_String;
Right : StringN.Unbounded_String) return Boolean is
begin
return String20.To_String(Left) = StringN.To_String(Right);
-- return Standard."="(String20.To_String(Left), StringN.To_String(Right));
end "=";
SB : constant String20.Bounded_String := 20 * '*';
SN : constant StringN.Unbounded_String := 20 * '*';
begin
Ada.Text_IO.Put_Line(String20.To_String(SB));
Ada.Text_IO.Put_Line(StringN.To_String(SN));
Ada.Text_IO.Put_Line(Boolean'Image(SB = SN)); -- infix operator
Ada.Text_IO.Put_Line(Boolean'Image("="(SB, SN))); -- named operator
end UseType;

In some cases, perhaps most or all cases, you shouldn't embed the logic that "two access-to-strings are equal if they are both null" into an abstraction (such as a package).
Consider the example where a bank transaction processing program reads the payee's name from two files, so ending up with data in Payee_Rec and Trans_Rec, which both have a Name field that is an access-to-string.
In this case, null means that the data (the payee's name) is not recorded, for some reason, in the record.
Somewhere we will check that the payee's name in both records is the same, and reject the transaction if they are not.
If the Names are of type lstring and the test we use looks like this:
if Payee_Rec.Name /= Trans_Rec.Name then
raise Validation_Error;
end if;
then if the two names are both null, this check will pass.
But it should not! If we don't even know what the payee's name is (in both records) the transaction should fail.
So my answer, while it may seem disappointing and even off topic, is "Don't do that."
I suggest that a well-written program would use Ada.String.Unbounded.Unbounded_String as the type (for both Name components, in the example above). If the source of the data (e.g. a database) can have null strings (for the names), then have a separate Boolean flag to indicate that, e.g. Name_Unknown.
The above example check could then be written in a very clear way:
if Payee_Rec.Name_Unknown
or Trans_Rec.Name_Unknown
or Payee_Rec.Name /= Trans_Rec.Name then
raise Validation_Error;
end if;
Note that you'll need the requisite use type ... to see the Unbounded_String equality (and inequality) operator.
You'd probably also want to validate both names that they are not empty strings or other nonsense, and you might want to do something more sophisticated than just raising an exception if a check fails.

You may want to use the NOT EQUAL operator negated, maybe? If you have no use for that operator, it is.
Which probably you shouldn't really need, because it is equivalent to not( X = Y )
Working the boolean algebra it should probably be something like:
FUNCTION "=" (lString1, lString2 : IN lString) RETURN boolean IS
IF not (lString1 /= NULL OR lString2 /= NULL) THEN
RETURN true;
ELSIF not(lString1 /= NULL AND lString2 /= NULL) THEN
RETURN false;
END IF;
PS: Test it, I didn't

Related

c++ equivelant to javascript OR

I am trying to implement a comparator function, and coming from a JavaScript background attempted to chain them like so:
int MyClass::compare(MyClass & other) {
return MyClass.x.compare(other.x) || MyClass.y.compare(other.y);
}
That is, compare the objects' x values, and if they are equal compare the objects' y values.
I immediately realized this wouldn't work, because the OR function in c++ returns a bool rather than the last evaluated value.
Other than literally writing an if statement, like
int result = MyClass.x.compare(other.x);
if (result) {
return result;
}
result = MyClass.y.compare(other.y);
return result;
, is there is a concise way to write this expression?

How to have a tri-state 'boolean' in c++

What is the best way to have three value Boolean variable in c++?
I would like to have fields set to true, false or not set at all in my array.
If I declare them this way:
t[0] = true;
t[1] = false;
t[2] = NULL;
When I test the condition I get:
t[2] is false
You might want to look at boost.tribool: http://www.boost.org/doc/libs/1_60_0/doc/html/tribool.html
This should work:
t[0] = true;
t[1] = false;
t[2] = -1;
Or if you only need 3 states but perhaps would like more at some point, an enum is great:
enum STATES
{
NULL_STATE = -1, // you can manually specify -1 to give it a special case value
FALSE, // will be equal to 0
TRUE // will be equal to 1
};
No matter what though, 0/false is the only thing that returns false in an if() statement. -1 and true both return true.
You may want to use a switch like this to deal with 3+ states:
switch (var) // may need to cast: (int)var
{
case 1:
case 0:
case -1:
};
Alternatively if you want to stick to an if statement block, you could do something like this:
if (var == -1) // or (var == NULL_STATE)
{}
else if (var) // true condition
{}
else // false
{}
Consider using std::experimental::optional<bool> (if your C++ standard library has it), or boost::optional<bool> (www.boost.org).
I believe std::optional is a candidate for C++17 so if you adopt one of the above then your refactoring effort to C++17 ought to be minimal.
If you don't like using things that are not (yet?) in the "proper" C++ standard library, then consider
Something based around std::unique_ptr<bool>
A std::pair<bool, bool>
A good old-fashioned enum with 3 values.
You could use boost::optional
http://www.boost.org/doc/libs/1_60_0/libs/optional/doc/html/index.html
boost::optional<bool> myBooleanVariable;
I agree that tribool can be better if you don't need the uninitialised values to be NULL. Where comparing optional and tribool, the documentation says:
First, it is functionally similar to a tristate boolean (false, maybe, true) —such as boost::tribool— except that in a tristate boolean, the maybe state represents a valid value, unlike the corresponding state of an uninitialized optional. It should be carefully considered if an optional instead of a tribool is really needed.
Source: http://www.boost.org/doc/libs/1_60_0/libs/optional/doc/html/boost_optional/a_note_about_optional_bool_.html
What is the best way to have three value Boolean variable in c++?
Boolean values by definition only have 2 possible states - True or False.
If you want to have another state for 'invalid' or 'not set' then you need to encapsulate the bool variable in some other data-types.
The right solution depends on what you want to do with that variable.
For simple comparisons (if-else and switch) scoped enums (c++11) should be preferred.
enum class tristate{true,false,undefined=0};
They are simple, easy to use and understand and offer type safety over plane old enums. As they are type-safe you can not accidentally compare it with different types of enums or numeral types, But it also means you can not use bitfiddling and integer-tricks either.
Unless a different type is specified an enum class is a numerical type which gets initialized to '0'. that means by assigning the value '0' to one of the enum-values you can make that the default state.
tristatet[7];
t[1] = tristate::true;
t[2] = tristate::false;
t[3] = tristate::undefined;
t[4] = false; //error
t[5] = 0; //error
t[6] = null; //error
t[0] == true; //error
t[0] == tristate::true; // false
t[0] == tristate::undefined; // true
Of course you can use that in a switch-statement:
switch(t[2]) {
case tristate::true:
foo(); break;
case tristate::false:
bar(); break; //t[2] was set to tristate::false
case tristate::undefined :
doNothing(); break;
}
You can use std::optional for this:
std::optional<bool> t[3];
t[0] = true;
t[1] = false;
t[2] = std::nullopt;
for (auto const& i : t)
if (i.has_value()) std::cout << i.value() << '\n';
output:
1
0
I also believe an enum declaration is the cleaner and simplest solution.
A small note on the size of the new type: enums are usually (depending of course on the compiler) backed by integers, so you are allocating something like 32 or 64 bits to actually use 2 bits.
In newer C++ (C++11), you can specify the underlying type of the enum (to an existing integral type). For example:
enum tribool: uint8_t {False = 0, True = 1, Unknown = 2};
...
enum tribool f = tribool::False;

What if I need to differentiate 0 from NULL in C++?

** Please don't criticize the purpose of the code itself. It's from Pat Morin's Open Data Structures book. Not my first choice, its assigned reading/practice. I just wanted to know if there is a way to differentiate, or a better way to go about this. Textbook--> http://opendatastructures.org/ods-cpp/**
** Another note: I'm coming from Java, where this would be allowed. My code still compiles, it just "fixes" it**
I'm surprised nothing like this has come up before because it seems like such a simple question. Perhaps it's buried or I'm not using the correct terminology.
I have a for loop that goes through the data in a vector. I need to return the value being searched for if it's found. What if it's not found? Here is my code.
int find(int x) {
for(int i=0;i<bag.size();i++){
// if x is equal to data, return data
if (bag[i]==x){
return bag[i]; // ends loop as soon as one instance is found
}
}
// if we made it this far, no match was found.
return NULL;
}
Pretty simple. Let's say 0 is one of the valid values that I might need to record and search for. As it is, it actually returns 0, not "NULL". Research says it is one and the same. How can I specify or differentiate? Other than returning an obsqure number that won't come up in the program because we may not always have that luxury (like -1 or -9999999). For example, searching for your account balance. No number is impossible.
Why would you return the value you are searching for from a find function? You already know the value, its the one you passed to the function. Return the position of the found element instead, as this information is much more useful. When the value isn't found, you can return a special position, like -1. Or you can follow the model of the standard library and return the end iterator, which signifies a position that is one past the end of the range.
You can write the function in several ways
bool find( int x )
{
std::vector<int>::size_type i = 0;
while ( i < bag.size() && bag[i] != x ) i++;
return i != bag.size();
}
Or
std::vector<int>::size_type find( int x )
{
std::vector<int>::size_type i = 0;
while ( i < bag.size() && bag[i] != x ) i++;
return i;
}
Or
#include <algorithm>
//...
std::vector<int>::iterator find( int x )
{
return std::find( beg.begin(), bag.end(), x );
}
And use the functions correspondingly the following ways
if ( find( x ) ) { /*...*/ }
if ( find( x ) != bag.size() ) { /*...*/ }
if ( find( x ) != bag.end() ) { /*...*/ }
As for your general question in the title of the post
What if I need to differentiate 0 from NULL in C++?
then you need fo use nullptr instead of NULL that to differentiate 0 from NULL.:)
#define XOR_MSB(x) (x^0x80000000)
int find(bool found) {
return found ? XOR_MSB(0) : NULL;
}
int main()
{
int value = find(false);
if (value == NULL) printf("not found\n");
else printf("%d\n", XOR_MSB(value));
value = find(true);
if (value == NULL) printf("not found\n");
else printf("%d\n", XOR_MSB(value));
return 0;
}
you're talking about an evil practice, coming from Java and C# developers where you can return null as invalid result.
well, you can't do it in C++.
Java and C# declares almost everything on the heap, and accessing objects is done done always by the reference. this means you always return a pointer from a function, and you can always return a null as a return value.
this is not so possible in C++ when a function does not return a pointer. for example , the function std::string returnString() can't return null as a return value.
more over, you should not return null as invalid output. this is wrong on so many levels even in C# and Java! if your function fails, simply throw an exception, or make your return value be passed as reference-argument and make the function return true or false.
you can also find less-agressive solutions like returning -1 (like indexOf() in javascript) or return somthing like std::string::npos or std::vector:end which are more C++ STL tuned.
This is what boost::optional<T> is for. Effectively, this type represents "There may be a T, but there may not be a T". The user may check if there is a T or not. Ideally you would not depend on any special value of T but use an optional<T> instead. optional<T> is fully generic and may apply to pretty much any T you may need to use, it does not depend on some special value or state of T.
boost::optional<int> find(int x) {
for(int i=0;i<bag.size();i++){
// if x is equal to data, return data
if (bag[i]==x){
return bag[i]; // ends loop as soon as one instance is found
}
}
// if we made it this far, no match was found.
return boost::none;
}
int main() {
if (auto opt = find(5))
std::cout << *opt;
}
Do not ever use NULL, it is a terrible thing. Always use nullptr which is substantially safer and one of the reasons why it is safer is because your wrong code would not compile.

what's wrong with declaring a variable inside if's condition?

Perhaps I am getting rusty (have been writing in Python recently).
Why does this not compile?
if ( (int i=f()) == 0)
without the () around the int i=f() I get another, much more reasonable error of i is not being boolean. But that's why I wanted the parentheses in the first place!
My guess would be that using the parentheses makes it into an expression, and that declaration statements are not allowed in an expression. Is it so? And if yes, is it one of the C++'s syntax quirks?
BTW, I was actually trying to do this:
if ( (Mymap::iterator it = m.find(name)) != m.end())
return it->second;
You can declare a variable in the if statement in C++ but it is restricted to be used with direct initialization and it needs to convert to a Boolean value:
if (int i = f()) { ... }
C++ doesn't have anything which could be described as "declaration expression", i.e. [sub-] expressions declaring a variable.
Actually, I just looked up the clause in the standard and both forms of initialization are supported according to 6.4 [stmt.select] paragraph 1:
...
condition:
expression
attribute-specifier-seqopt decl-specifier-seq declarator = initializer-clause
attribute-specifier-seqopt decl-specifier-seq declarator braced-init-list
...
That is, it is also be possible to write:
if (int i{f()}) { ... }
Obviously, this only works in C++2011 because C++2003 doesn't have brace-initialization.
There's a problem with scope.
Consider the following code:
if ((int a = foo1()) || (int b = foo2()))
{
bar(b);
}
Is b declared inside the block? What if foo1() returns true?
You can declare a variable in an if statement (or in for or while), but only in the outer parenthesis block and it needs to be able to be converted to bool.
Your guess is basically right, it's not allowed because
(int i = 42;)
is not a valid declaration with initialization.
You need one additional line,
Mymap::iterator it;
if ( (it = m.find(name)) != m.end())
return it->second;
but then it's better to write
Mymap::iterator it = m.find(name);
if ( it != m.end() )
return it->second;
You can put the return line after the if, if you really want this line back, at least for me this doesn't harm readability, but others might see that different.
If you really, really want to declare an iterator and use the it as bool in an if condition, you could do
if ( struct { int it; operator bool() { return it != m.end; } } s = { m.find(name) } )
return s.it->second;
but I would consider this harmful ;-)
It's true that you can't write
if ( (int i=f()) == 0)
but you can perfectly write
if ( int i=f())
So you can use the && operator to perform both operations in one statement like
if ( int i=1 && (i=f()) == 0)
i should be initialized with any value other than 0, and it should be the first condition if your compiler applies left-to-right evaluation.
But unfortunately, that's not applicable in case of iterators as your second example asks.

comparison operator

It may be silly question.
Is there any way to give comparison operator at runtime using string variable.
Suppose i have a data of salaries in vector.
vector < int > salary;
Input:
salary[i] != /* ==,>,<,>=,<= (any comparison operator)) */ 9000.
The input given like above. I store the comparison operator in string str. str = (any comparison operator). Is there any way to check like this without if and switch.
salary str 9000
You can create a map with operator-strings as keys and function objects for corresponding comparison operations as values.
Creating a map:
std::map<std::string, boost::function<bool(int, int)> > ops;
ops["=="] = std::equal_to<int>();
ops["!="] = std::not_equal_to<int>();
ops[">"] = std::greater<int>();
ops["<"] = std::less<int>();
ops[">="] = std::greater_equal<int>();
ops["<="] = std::less_equal<int>();
Using it:
bool resultOfComparison = ops[str](salary[i], 9000);
(See this link for a complete working example.)
EDIT:
As #sbi said in the comments below, accessing a map using map[key] will create an entry if the key didn't exist. So use it = map.find(key) instead. If the result is equal to map.end() the key wasn't found, otherwise value is it->second. Take note of this while adapting this solution to your needs.
Still, you might have a std::map with a mapping between contents of your strings and pointers to your operators.
No. Not possible. Unless you parse the given input and call the corresponding operation. In any case, you would need a if - else statement.
You need to have something of sort of EVAL in your programming language, which evaluates your strings.
EDIT: C++ does not have EVAL to support your cause.
No, compiled languages like C++ don't work like that. There has to be code in the final executable that does the comparison, and by design C++ doesn't generate that code unless it's actually in the source program.
You can also create a functor which will take string as a constructor or factory which will produce different functors (depending on flexibility you need).
So something like:
:Input
Comp cmp = Comp(str);
if (cpm(salary[i], 9000))
{
cout << "wow";
}
You'd have to "hack" in this required eval! ;) i.e.
template <typename T>
bool eval_op(const string& op, const T& lhs, const T& rhs)
{
switch(op.size())
{
case 2:
{
switch(op[1])
{
case '=':
{
switch(op[0])
{
case '=': return lhs == rhs;
case '!': return lhs != rhs;
case '>': return lhs >= rhs;
case '<': return lhs <= rhs;
}
}
default: throw("crazy fool!");
};
}
case 1:
{
switch(op[0])
{
case '>': return lhs > rhs;
case '<': return lhs < rhs;
default: throw ("crazy fool!");
}
}
default: throw ("crazy fool!");
}
return false;
}
DISCLAIMER: I've not tested this... but it's an idea...
In this particular situation an if-else branch is your simplest solution. This is simply because there are only so many comparison alternatives, and you can be sure none others will ever exist. In essence your code should be along the lines of
if( in == "==" )
cond = salary[i] == 9000;
else if( in == "!=" )
cond = salary[i] != 9000;
// ...
else
// throw, return -1, raise a flag or burst out in laughter
This is in fact safer than a dynamic eval() because here you sanitize the input. You make sure there is no malicious code in there, along the lines of a Little Bobby Tables attack.
Granted, you could use polymorphism here, but the point of polymorphism is support open-ended type alternatives. When you wish to add a case, polymorphism allows you to do that with ease. But you'd need to do some work to get foundations up, and here there are exactly 6 comparison alternatives. Or 7, if you want to add support for an arbitrary predicate.