Ada - Operator subprogram - operators

Create a subprogram of type operator that receives two integers and sends them back
the negative sum of them. I.e. if the sum is positive it will be
the result is negative or if the sum is a negative result
positive. Ex. 6 and 4 give -10 as a result and 2 and -6 give 4.
For instance:
Type in two integers: **7 -10**
The negative sum of the two integers is 3.
Type in two integers: **-10 7**
The positive sum of the two integers is -3.
No entries or prints may be made in the subprogram.
So I attempted this task and actually solved it pretty easily using a function but when it came to converting it to an operator I stumbled into a problem.
This is my approach:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
procedure Test is
function "+" (Left, Right : in Integer) return Integer is
Sum : Integer;
begin
Sum := -(Left + Right);
return Sum;
end "+";
Left, Right : Integer;
begin
Put("Type in two integers: ");
Get(Left);
Get(Right);
Put("The ");
if -(Left + Right) >= 0 then
Put("negative ");
else
Put("positive ");
end if;
Put("sum of the two integers is: ");
Put(-(Left + Right));
end Test;
My program compiles but when I run it and type two integers it says:
raised STORAGE_ERROR: infinite recursion
How do I solve this problem using an operator? I managed to tackle it easily with the procedure- and function subprogram but not the operator. Any help is appreciated!

You can use the type system to solve this without using a new operator symbol.
As a hint, operators can overload on argument and return types. And a close reading of the question shows the input type is specified, but not the output type. So, how about this?
type Not_Integer is new Integer;
function "+" (Left, Right : in Integer) return Not_Integer is
Sum : Integer;
begin
Sum := -(Left + Right);
return Not_Integer(Sum);
end "+";
As the two "+" operators have different return types, there is no ambiguity between them and no infinite recursion.
You will have to modify the main program to assign the result to a Not_Integer variable in order to use the new operator.

Related

My macro is not assignable

I'm trying to define a macro that returns an absolute value of numbers. Here how it looks like:
#define ABSOLUTE_VALUE(v) ( (v) < 0 ? (v) *= -1 : (v))
It works fine when I insert just a single number. The problem is, when I try to insert an expression (number + anotherNumber, for example), the compiler throws an error, saying that the expression is not assignable. I can't figure out why it does that. If you know the reason of the error, I would appreciate your help.
What's going on here is that the entire expression number + anotherNumber is getting passed to your macro, so anywhere there is v, it's not the result v = number + anotherNumber, rather, v is replaced by number + anotherNumber before evaluation. So:
(v) *= -1
Becomes
(number + anotherNumber) *= -1
Since number + anotherNumber is yet another number, that part of the code is trying to assign the value of -1 * (number + anotherNumber) to number + anotherNumber , which results in the error you are seeing, because you can't assign something to an expression.
From one of your comments:
The problem is that I'm trying to assign the result of (number + anotherNumber) * (-1) to an expression, which is number + anotherNumber. But shouldn't the + fire first, before the *= operator?
You are misunderstanding assignment. The left hand side (LHS) of an assignment must be an lvalue, which means something like a variable, which references a storage location into which values can be stored.
A value is just that, it is not associated with any storage location, you cannot assign to it. The result of your expression number + anotherNumber is a number, it cannot go on the LHS of an assignment.
Your macro would work if you simply replace =* with *.
HTH

Can’t use record’s discriminant within the record

My code is below. The compiler won’t let me use the discriminant var to control the size of the string name.
procedure p is
type int is range 1 .. 10;
type my (var : int) is record
name : string (1 .. var); -- this var here is bad, why?
end record;
hh : my(6);
begin
put (hh.name);
end p;
The error messages are
p.adb:4:23: expected type "Standard.Integer"
p.adb:4:23: found type "int" defined at line 2
It's due to Ada strong typing. Ada allows you to declare new integer and floating-point types which are not compatible with each other. The original intent was to prevent accidentally using values with one meaning as if they had a totally unrelated meaning, e.g.
type Length is digits 15; -- in meters
type Mass is digits 15; -- in kilograms
L : Length;
M : Mass;
M := L; -- error, caught at compile time
The compiler catches this statement that doesn't make any sense because a "mass" variable can't hold a length. If everything were just Float or Long_Float the compiler wouldn't be able to catch it.
What you've done is to create another integer type, int. As in the above example, values of your new type can't automatically be converted to Integer, which is the type of the index of String. (String is actually defined as array (Positive range <>) of Character with Pack;, but Positive is a subtype of Integer, and values can be automatically converted between Positive and Integer since they are really subtypes of the same base type.)
Unfortunately, this isn't allowed either:
type my(var : int) is record
name : string (1 .. Integer(var)); -- this var here is bad why?
end record;
because of an Ada rule that the discriminant has to appear alone in this context. So your only option is to make int a subtype:
subtype int is Integer range 0 .. 10;
type my(var : int) is record
name : string (1 .. var); -- this var here is bad why?
end record;

Function format number

For oracle,
Can anyone fixes the function below to let it works with "a number (10,2)"? Just this condition only.
Here I come with the function..
CREATE OR REPLACE FUNCTION Fmt_num(N1 in NUMBER)
RETURN CHAR
IS
BEGIN
RETURN TO_CHAR(N1,'FM9,9999.99');
END;
/
And I can use this with the SQL statement as follow
SELECT Fmt_num(price) from A;
That depends on what you mean by "works" and what output you want. My guess is that you just want to update the format mask
to_char( n1, 'fm999,999,999.99' )
That assumes, though, that you want to use hard-coded decimal points and separators and that you want to use the American/ European convention of separating numbers in sets of 3 rather than, say, the traditional Indian system of representing large numbers.
CREATE OR REPLACE FUNCTION Fmt_num(N1 in NUMBER)
RETURN CHAR
IS
BEGIN
RETURN TO_CHAR(N1,'FM99,999,999.99');
END;
/
If you really want the comma every 4 digits, you could do this:
TO_CHAR(N1,'FM9999,9999,9999.99');
However, I'd recommend you use the locale-safe version (G for the grouping character, D for the decimal separator):
TO_CHAR(N1,'FM9999G9999G9999D99');

min function in PL/SQL

I want to choose the min value in two date ,such as
c := min(a,b);
It occupy compiler error :
Error(20,10): PLS-00103: Encountered
the symbol "," when expecting one of
the following:
. ( ) * # % & - + /
at mod remainder rem || multiset
I know we can use aggregate function Min in the SQL. I dan't whether there is the similar func i can use i pl/sql?
In PLSQL, the least function returns the smallest value in a list of expressions.
LEAST("ColumnName", _NumberOfRows)
Example: For the Minimum 5 Rows = LEAST(Price,5)

Oracle SQL and PL/SQL : how to minimize execution time of retrieving members of the object (returned by user's function)

I wrote a function to get a number of values in an Oracle view. As functions can't return more then one value, I have used an object (with a signature of 8 numbers). This works, but not fine...
The execution time of a select query (and selecting from view, based on this query) is proportional to retrieved members number, i.e.:
retrieving 1 attribute consumes 1 second (it's equal to retrieve a WHOLE object, but object value is unusable for report),
retrieving 2 attributes consumes 2 seconds,
and so on...
This looks like Oracle executes PL function to get every member of returned object.
I think that function, returning varray(8) of numbers will not solve the problem too: eight implicit calls must be replaced by eight explicit subqueries. Can anybody solve this problem? (Except to rewrite to use a function returning one string, which I will try myself now...)
Here is the type declaration:
create or replace type "ARD"."PAY_FINE_FR_12_" AS object
(fed1 number
, reg1 number
, fed_nach number
, reg_nach number
, fed_upl number
, reg_upl number
, fed2 number
, reg2 number);
I will assume you have given meaningful names to your type's attributes. In which case you are returning not eight numbers but four pairs of numbers. This suggests a possible way of improving things. Whether it could actually solve your problem will depend on the precise details of your situation (which you have not provided).
Here is a type representing those number pairs, and a nested table type we can use for array processing.
create or replace type pay_pair as object
( pay_cat varchar2(4)
, fed number
, reg number )
/
create or replace type pay_pair_nt as table of pay_pair
/
This is a function which populates an array with four pairs of numbers. In the absence of any actual business rule I have plumped for the simplest possible example.
create or replace function get_pay_pairs
return pay_pair_nt
is
return_value pay_pair_nt;
begin
select
pay_pair (
case col1
when 1 then 'one'
when 2 then 'nach'
when 3 then 'upl'
when 4 then 'two'
else null;
end
, fed
, pay )
bulk collect into return_value
from v23;
return return_value;
end;
/
If you need the signature of the original type you can rewrite your function like this:
create or replace function get_pay_fine
return PAY_FINE_FR_12_
is
return_value PAY_FINE_FR_12_;
l_array pay_pair_nt;
begin
l_array := get_pay_pairs;
for i in 1..4 loop
case l_array(i).pay_cat
when 'one' then
return_value.fed1 := l_array(i).fed;
return_value.reg1 := l_array(i).reg;
when 'nach' then
return_value.fed_nach := l_array(i).fed;
return_value.reg_nach := l_array(i).reg;
when 'upl' then
return_value.fed_upl := l_array(i).fed;
return_value.reg_upl := l_array(i).reg;
else
return_value.fed2 := l_array(i).fed;
return_value.reg2 := l_array(i).reg;
end case;
end loop;
return return_value;
end;
I'll repeat, this is a demonstration of available techniques rather than a proposed solution. The crux is how your view supplies the values.