Error code: VUTA(3) Error: separate target of the Object_call is not controlled - eiffel

I'm a complete beginner to Eiffel and I'm implementing a linked list as an exercise. I get the following error in the feature has (which tells you if the list contains v).
Error code: VUTA(3)
Error: separate target of the Object_call is not controlled.
What to do: ensure the target of the call is controlled or is not separate.
Class: MY_LINKED_LIST [G]
Feature: has
Type: Generic #1
Line: 159
then
-> if l_cursor_a.item.is_equal (v) then
Result := True
The weird thing is that when I change the '.is_equal' for a '=' the error is gone. I don't know what 'controlled' in the error description means and what difference to it does make to use '=' in this context. The code is the following:
MY_LINKED_LIST[G]
class
MY_LINKED_LIST[G]
feature -- Access
item: G
require
not off
do
check
off: attached cursor as l_cursor
then
Result := l_cursor.item
end
end
first,
last: detachable like item
feature -- Measurement
count: INTEGER
feature -- Element change
feature -- Status report
index: INTEGER
before: BOOLEAN
after: BOOLEAN
has (v: like item): BOOLEAN
require
local
l_cursor: like cursor
do
from
l_cursor := first_element
until
not attached l_cursor or Result
loop
check
attached l_cursor as l_cursor_a
then
if l_cursor_a.item.is_equal (v) then
Result := True
end
l_cursor := l_cursor_a.next
end
end
ensure
function_not_change_state: item = old item
end
feature {NONE} -- Implementation
cursor,
first_element,
last_element: detachable MY_CELL[G]
end -- class
MY_CELL[G]
class
MY_CELL[G]
feature -- Access
item: G

The error message is related to SCOOP — the model of concurrent programming built into Eiffel. According to it, a feature can be called on a separate object only when the object is controlled. This is achieved when the target of the call is an argument of a feature, or when a special separate instruction is used. In your case, the latter would look like
separate l_cursor_a.item as x do
if x.is_equal (v) then
Result := True
end
end
Why l_cursor_a.item is considered separate in the first place? It has a type G, and the formal generic is unconstrained that is identical to have a constraint detachable separate ANY (so, most probably, the code above would not compile, you would need to make sure x is attached before calling is_equal on it).
The equality operator = does not perform any calls (unless the involved types are expanded, but expanded types are never separate). For reference types (including separate ones), it simply tests whether two references are the same. This explains why the error disappears when is_equal is replaced with =.
An alternative solution to avoid the error message is to change the constraint of the formal generic to be non-separate: MY_LINKED_LIST [G -> detachable ANY].
Side note. The check instruction check attached l_cursor as l_cursor_a then ... seems to be redundant, the compiler should be able to figure out automatically that l_cursor is attached.

Related

Implementation contraint: The class feature only_from_type uses an inline agent

Is there a semantic behind not being able to have an agent into a ensure class routine or is it a current compiler restriction?
only_from_type (some_items: CHAIN[like Current]; a_type: detachable like {ENUMERATE}.measuring_point_type_generation): LINKED_LIST[like Current]
-- extends Result with given some_items which are equal to given type
do
create Result.make
across
some_items is l_item
loop
check
attached_type: attached l_item.type as l_type
then
if attached a_type as l_a_type and then l_type.is_equal (l_a_type) then
Result.extend (l_item)
end
end
end
ensure
some_items.for_all (
agent (an_item: like Current; a_type_2: detachable like {ENUMERATE}.measuring_point_type_generation) do
if attached a_type_2 as l_type_2_a and then
attached an_item.type as l_item_type and then
l_item_type.is_equal (l_type_2_a)
then
Result := True
end
end (a_type)
)
instance_free: Class
end
gives following error
And I think there is a typo here, shouldn't it be Implementation constraint instead of contraint?
Error code: VUCR
Implementation contraint: The class feature only_from_type uses an inline agent.
What to do: Remove the inline agent from the code or make the feature a non-class one.
Class: MEASURING_POINT
Feature: only_from_type
Line: 183
some_items.for_all (
-> agent (an_item: like Current; a_type_2: detachable like {ENUMERATE}.measuring_point_type_generation) do
if attached a_type_2 as l_type_2_a and then
An inline agent (like a regular feature) takes an implicit argument - current object. In a class feature (where it is used in the example), there is no current object. Therefore, an inline agent cannot be called from a class feature.
On the other hand, it might be possible to check that the agent does not use Current, and, therefore, is safe to use in the class feature. The compiler reporting the error does not implement such a functionality, and reports an implementation constraint error instead.

How to call a function with void return using Firedac FDConnection Component in Delphi XE5?

I recently started using the [ExecSQLScalar]1 and [ExecSQL]2 methods of the FDConnection component in Delphi XE5. It's very handy not to need to build a Dataset object, like FDQuery just for simple queries or executions.
However I had a curious problem when executing a function with void return that has internal validations where it can generate exceptions. I'm using a Postgres database.
CREATE FUNCTION can_be_exception()
RETURNS void AS
$$
BEGIN
RAISE EXCEPTION E'fail';
END;
$$
LANGUAGE plpgsql STABLE;
In delphi, I call the ExecSQLScalar function ...
FDConnection1.ExecSQLScalar('select 1');
FDConnection1.ExecSQLScalar('select can_be_exception()');
On first run, I get the following error:
Project TFDConnectionDEMO.exe raised exception class
EPgNativeException with message '[FireDAC][Phys][PG][libpq] ERROR:
fail'.
On the second run, I get a Violation Access error:
Project TFDConnectionDEMO.exe raised exception class $C0000005 with
message 'access violation at 0x00000000: read of address 0x00000000'.
Apparently the error occurs in the line below in unit FireDAC.Comp.Client
function TFDCustomConnection.ExecSQLScalar(const ASQL: String;
const AParams: array of Variant; const ATypes: array of TFieldType): Variant;
var
oCmd: IFDPhysCommand;
begin
oCmd := BaseCreateSQL;
try
if BasePrepareSQL(oCmd, ASQL, AParams, ATypes) or (FExecSQLTab = nil) then begin
FDFree(FExecSQLTab);
...
ignoring the previous error and trying again, another error is displayed...
Project TZConnectionDEMO.exe raised exception class EFDException with
message '[FireDAC][DatS]-24. Row is not nested'.
Searching, I found no response to this error. I figured my mistake would be to call the bank raise_exception function using the ExecSQLScalar function of the FDConnection component. So I tried using FDConnection.ExecSQL and as I imagined, you can not use this if there is a SELECT clause in the parameter.
Is there a better way to call function with void return using FDConnection.ExecSQL? would a BUG be in the component? or would not it be correct to make that kind of call?
Using ExecSQLScalar is fine in this case. This is certainly a bug (which was already fixed, at least in Delphi 10.2.3). As you've correctly pointed out, the problem is in releasing a table storage object instance held by the FExecSQLTab field by using FDFree procedure.
I don't have Delphi XE5 source code but maybe you can see something like this inside (comments about what happened are added by me):
if BasePrepareSQL(oCmd, ASQL, AParams, ATypes) or (FExecSQLTab = nil) then
begin
FDFree(FExecSQLTab); { ← directly calls destructor if object is not nil }
FExecSQLTab := oCmd.Define; { ← no assignment if command execution raises exception }
end;
Problem was that when a SQL command execution raised exception during storage table definition stage (oCmd.Define), reference to previously destroyed storage table object instance (by FDFree) remained stored in the FExecSQLTab field (as a dangling pointer).
Then when a different command was executed that way, FDFree procedure was called just for that dangling pointer. Hence the access violation.
Way to correct this is replacing line e.g. by:
FDFree(FExecSQLTab);
by:
FDFreeAndNil(FExecSQLTab);
which was done in some later Delphi release.

Ada : operator is not directly visible

I'm using GNAT GPS studio IDE in order to train a bit in Ada. I'm having an issue with package visibility.
First I specify a package in a file called "DScale.ads" containing a type:
package DScale is
type DMajor is (D, E, F_Sharp, G, A, B, C_Sharp);
end DScale;
Then I specify in a different file ("Noteworthy.ads") a package that defines a procedure that will use the DMajor type of the DScale package:
with Ada.Text_IO;
with DScale;
package NoteWorthy is
procedure Note;
end NoteWorthy;
Finally in "Noteworthy.adb" I provide the package body for the package "Noteworthy":
with Ada.Text_IO; use Ada.Text_IO;
package body Noteworthy is
procedure Note is
package ScaleIO is new Enumeration_IO(DScale.DMajor);
thisNote : DScale.DMajor := DScale.D;
begin
ScaleIO.Get(thisNote);
if thisNote = DScale.DMajor'First then
Put_Line("First note of scale.");
end if;
end Note;
begin
null;
end NoteWorthy;
If I leave the code as-is, I will get an "operator not directly visible" error for the "if thisNote = DScale.DMajor'First then" statement in the body of the "Noteworthy" package.
Is there a way to bypass this error without using a "use" or "use type" clause?
Thank you.
There are (at least) two answers to your question.
1:
if DScale."=" (thisNote, DScale.DMajor'First) then
2:
function "=" (Left, Right : DScale.DMajor) return Boolean renames DScale.DMajor;
...
if thisNote = DScale.DMajor'First then
But why would you use one of those options instead of:
use type DScale.DMajor;
...
if thisNote = DScale.DMajor'First then
Ada types are much more than just descriptions of the values, they are entities that bring into existence a whole slew of operations, embodied as both operators and attributes. So if you want direct visibility to a type's concrete "=" operator, you have to make it visible. For that you need either "use" or "use type".
Why bypass a language feature? Simply use it wisely.
A couple of points that are related to the structure of your code.
The package spec for Noteworthy doesn't need to "with DScale" as there is nothing in the spec that refers to any feature in that package (maybe you plan to in the future).
The use of enumeration_io is good if you want to simply want to do I/O to files to be read by a computer, but I would never use it for human interaction (apart from quick hacks). The input values it accepts is dictated by Ada's grammar, and typically not what user's expect.

Ada and SPARK identifier `State` is either undeclared or not visible at this point

I am doing an automatic train protection on Ada with SPARK approach. This is my spec in SPARK:
package Sensors
--# own State,Pointer,State1,State2;
--# initializes State,Pointer,State1,State2;
is
type Sensor_Type is (Proceed, Caution, Danger, Undef);
subtype Sensor_Index_Type is Integer range 1..3;
procedure Write_Sensors(Value_1, Value_2, Value_3: in Sensor_Type);
--# global in out State,Pointer;
--# derives State from State,Value_1, Value_2, Value_3,Pointer &
--# Pointer from Pointer;
function Read_Sensor(Sensor_Index: in Sensor_Index_Type) return Sensor_Type;
function Read_Sensor_Majority return Sensor_Type;
end Sensors;
and this is my Ada:
package body Sensors is
type Vector is array(Sensor_Index_Type) of Sensor_Type;
State: Vector;
Pointer:Integer;
State1:Sensor_Type;
State2:Sensor_Type;
procedure Write_Sensors(Value_1, Value_2, Value_3: in Sensor_Type) is
begin
State(Pointer):=Value_1;
Pointer:= Pointer + 1;
State(Pointer):=Value_2;
Pointer:= Pointer + 1;
State(Pointer):=Value_3;
end Write_Sensors;
function Read_Sensor (Sensor_Index: in Sensor_Index_Type) return Sensor_Type
is
State1:Sensor_Type;
begin
State1:=Proceed;
if Sensor_Index=1 then
State1:=Proceed;
elsif Sensor_Index=2 then
State1:=Caution;
elsif Sensor_Index=3 then
State1:=Danger;
end if;
return State1;
end Read_Sensor;
function Read_Sensor_Majority return Sensor_Type is
State2:Sensor_Type;
begin
State2 := state(1);
return State2;
end Read_Sensor_Majority;
begin -- initialization
State:=Vector'(Sensor_Index_Type =>Proceed);
pointer:= 0;
State1:=Proceed;
State2:=Proceed;
end Sensors;
I want to know why in the function Read_Sensor_Majority I can't use the State(1) or any of the State() array values. If there is a way to use them, should I put anything in the specs of SPARK to make it happen?
The errors it's showing are:
1)Expression contains referenced to variable state which has an undefined value flow error 20
2)the variable state is nether imported nor defined flow error 32
3)the undefined initial value of state maybe used in the derivation of the function value flow error 602
You need to change the spec to read
function Read_Sensor_Majority return Sensor_Type;
--# global in State;
As I said in the comments above, I was puzzled by
State := Vector'(Sensor_Index_Type => Proceed);
but the compiler accepts it so it must be OK. And a little test shows that it has the same effect as
State := Vector'(others => Proceed);
Also pleased to report that the SPARK GPL 2011 toolset is now available for Mac OS X!
Heh. Well, those are definitely SPARK errors, rather than "garden variety" compiler errors.
It would be nice to see an actual cut-and-paste version of the errors (along with an indication of which lines they are referring to) rather than just an imperfect transcription. However, I do realise that isn't always possible for security/connectivity reasons.
It looks like all three are complaining about the flow of data through your system. Without knowing which lines they refer to, the best I can suggest is to try to manually trace your flow of data through your system to try to see what their problem is.
If I had to take a wild guess with the info I have here, I'd say it perhaps has a problem with your reading of a value from State(1) in the routine Read_Sensor_Majority, because it has no way of knowing that you've previously placed a value into that array location.
The code you have in the package's begin...end body area should take care of that, except it appears to have a compile error itself, as Simon pointed out in the comments. Perhaps if you fix that problem, SPARK will understand what is going on and quit complaining about your control flows.
If SPARK likes to spit out "I'm confused" errors on code that doesn't even get past the Ada compiler, it might be wise to make sure the Ada compiler likes the pure Ada part of your code before asking SPARK to look it over.

DELPHI class with dynamic array has problem with SetLength()

I need to create a class containing an array of record objects but trying to use SetLength raise an Access Violation errror.
Consider the following example of a tree object with fruits.
type
TFruit = record
color: string;
weight: double;
end;
type
TObjectTree = class
Public
Fruits: array of TFruit;
constructor Create;
procedure AddFruit;
end;
In the implementation, when trying to resize the array of Fruit objects or initializing to nil generates problems.
constructor TObjectTree.Create;
begin
inherited Create;
Fruits:=nil; //Raises an error
end;
procedure TObjectTree.AddFruit(FruitColor: string; FruitWeight: integer);
begin
SetLength(Fruits, Length(Fruits)+1); //Raises an error (when I comment Fruits:=nil; in the constructor)
Fruits[Length(Fruits)].color:=FruitColor;
Fruits[Length(Fruits)].weight:=FruitWeight;
end;
How can I use dynamic arrays in a class?
Replace
Fruits[Length(Fruits)].color:=FruitColor;
Fruits[Length(Fruits)].weight:=FruitWeight;
with
Fruits[High(Fruits)].color:=FruitColor;
Fruits[High(Fruits)].weight:=FruitWeight;
then it works.
Something tells me you've neglected to create an instance of TObjectTree. You've declared a TObjectTree variable, but you've either not called TObjectTree.Create, or you've called it directly on the variable you declared instead of assigning a new value to that variable:
var
Tree: TObjectTree;
begin
// This is wrong.
Tree.Create;
// This is right.
Tree := TObjectTree.Create;
Without properly instantiating TObjectTree, there is no valid memory to back the Fruits field you attempt to use, so assigning a value to it gives an error.
As an addition to the answers of iamjoosy and Rob Kennedy, I would code this like so:
procedure TObjectTree.AddFruit(FruitColor: string; FruitWeight: integer);
var
NewCount: Integer;
begin
NewCount := Length(Fruits)+1;
SetLength(Fruits, NewCount);
Fruits[NewCount-1].color := FruitColor;
Fruits[NewCount-1].weight := FruitWeight;
end;
It is clearer, in my view, to call Length() just once.
You do not need to assign Fruits := nil in the constructor since that happens automatically. All fields are zero-initialised when an object is instantiated. That said, Fruits := nil should not raise an error. If it does it is probably a result of a memory corruption due to the out-of-bounds array accessing.
A further point to make is that enabling range checking would have resulted in an informative error that would have explained the problem. This is much more helpful than relying on access violations. I can't recommend range checking highly enough.
Finally, the SetLength(..., Length(...)+1) pattern typically leads to very inefficient memory usage and can lead to performance problems for large lists. If you have Delphi 2009+, I would recommend using TList<TFruit> instead.

Resources