Pass class to record - delphi

I want define constant with records where one variable is class.
And receive error:
[DCC Error] usample.pas(18): E2026 Constant expression expected
Class and record declaration in Unit1:
type TParentClass = class (TObject)
function Call(s: string) : boolean;
end;
type TMyRecord = record
s: string;
c: TParentClass; //or TClass
end;
And Unit2 with Child Class and record:
type TChildClass = class (TParentClass);
procedure two;
var:
class_var: TChildClass;
const
rec_var : array[0..1] of TMyRecord = (
(s : ''; c : class_var) //Error with class_var.
);
UPD: I want to fill record with Class and in unit1 search functions in this Class. Its a team project.
UPD2:
const
class_var: TChildClass = nil;
Same error.

Because as the compiler says, you have to put a constant in there, but you defined class_var as a variable.
Change class_var to be declared as a constant, not a variable.
But this cannot actually be done:
const
class_var = TParentClass;
is not allowed.
And
const
class_var : TClass = TParentClass;
is not a real constant and you cannot use it inside another constant declaration.

In your latest update you ask why this does not compile:
const
class_var: TChildClass = nil;
rec_var: TMyRecord = (s: ''; c: class_var);
The reason that does not compile is that class_var is not a true constant. You can write it like this:
rec_var: TMyRecord = (s: ''; c: nil);
because nil is a true constant.
I'm struggling to get a handle on what you are really trying to do, but my instincts tell me that a constant is not what you need. I think you are going to need to use variables that are initialized at startup.

You cannot define a const with a field initialized to the content of a variable. The compiler needs to evaluate consts at compile time, ie when class_var does not even have a location, never mind any content.
Forget this idea. If you can, declare rec_var as a variable and load it up at runtime.

Related

How to assign a constant value as default value in constructor

class Foo {
final int x;
Foo([this.x = defValue]); // Compile-time error
static get defValue => 10;
}
Error:
The default value of an optional parameter must be a constant.
defValue is a compile time constant, so I should be able to pass its value to the constructor.
The expression defValue is not a compile-time constant expression. Evaluating it requires executing the getter to get a value, and constant evaluation cannot execute getters or methods (except a very specific list of allowed platform methods, like int.operator+). It might be that the expression returned by executing the defValue getter is itself a compile-time constant expression, but it's being returned through a non-constant operation.
Change the defValue definition to
static const defValue = 10;
then it should work. Reading constant declarations is a compile-time constant operation.
You refer to the docs saying that you can use a static method as a compile-time constant. That is correct, but that's the method itself which is the constant, you are still not allowed to call it.
That is:
static int foo(int x) => x;
static const fooRef = foo; // valid!
works because referencing the foo function value is a constant expression.
A getter is not a method, and you cannot do a "tear-off" of the getter. When you refer to it, you need to execute its body, and that's not allowed in a constant context.
My guess is that defValue is not known at compile time (since it's a getter and not a constant), so you should either use a constant variable like static const int defValue = 10 or initialize the class like this:
class Foo {
final int x;
Foo([int x]) : this.x = x ?? defValue;
static get defValue => 10;
}

How can I call a procedure declared inside another procedure?

I have a doubt regarding procedures in Db2. I created a stored procedure using "CREATE PROCEDURE", and inside that I have another which is declared using "DECLARE PROCEDURE". But, this procedure created by declare, cannot be called using "CALL".
When I try to run the procedure, Db2 returns:
[Code: -440, SQL State: 42884] DB2 SQL Error: SQLCODE=-440,
SQLSTATE=42884,
SQLERRMC=DMTLDBR.SP_DASH_CALENDARIO.PROCURA_DIA_UTIL_POST_DIA1;PROCEDURE,
DRIVER=4.25.1301
How should I call the declared procedure? (PROCURA_DIA_UTIL_POST_DIA1)
Code:
create or replace PROCEDURE "SP_DASH_CALENDARIO" (IN P_MES INTEGER)
BEGIN
------
DECLARE SQLSTATE CHAR(5) DEFAULT ' ';
DECLARE V_ANO_MES DECIMAL(6);
DECLARE V_ID_DIA ANCHOR DATA TYPE TO DMTLDBR.TB_DIM_DIADIA.ID_DIA;
DECLARE V_VAL_REAL_CAL ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_VENDASDIARIO.VAL_TONLIQUIDO;
DECLARE V_VAL_TONVNEMA ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_VENDASDIARIO.VAL_TONVNEMA;
DECLARE V_VAL_FAT357_CAL ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_VENDASDIARIO.VAL_FAT357;
DECLARE V_VAL_PERDA_FAT_CAL ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_VENDASDIARIO.VAL_PERDA;
DECLARE V_SUM_VAL_REAL_CAL ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_DASH_CALENDARIO.VAL_REAL_CAL;
DECLARE V_SUM_VAL_TONVNE_CAL ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_DASH_CALENDARIO.VAL_TONVNE_CAL;
DECLARE V_SUM_VAL_TONLIQUIDO_ZBCL_CAL ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_DASH_CALENDARIO.VAL_TONLIQUIDO_ZBCL_CAL;
DECLARE V_SUM_VAL_TONLIQUIDO_CAL ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_DASH_CALENDARIO.VAL_TONLIQUIDO_CAL;
DECLARE V_SUM_VAL_FAT357_CAL ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_DASH_CALENDARIO.VAL_FAT357_CAL;
DECLARE V_VAL_TONLIQUIDO_CAL ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_DASH_CALENDARIO.VAL_TONLIQUIDO_CAL;
DECLARE V_VAL_TONVNE_CAL ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_DASH_CALENDARIO.VAL_TONVNE_CAL;
DECLARE V_VAL_TONLIQUIDO_ZBCL_CAL ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_DASH_CALENDARIO.VAL_TONLIQUIDO_ZBCL_CAL;
DECLARE V_VAL_PLANO_FAT_CAL ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_PLANEJ_MAN.VAL_PLANO;
DECLARE V_VAL_PLANO ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_PLANEJ_MAN.VAL_PLANO;
DECLARE V_TOTAL_PLANO_DESOVA_SEMANAL ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_PLANEJ_MAN.TOTAL_PLANO_DESOVA_SEMANAL;
DECLARE V_ID_DIASEMANA ANCHOR DATA TYPE TO DMTLDBR.TB_DIM_DIADIA.ID_DIASEMANA;
DECLARE V_FLG_HOLIDAY ANCHOR DATA TYPE TO DMTLDBR.TB_DIM_DIADIA.FLG_HOLIDAY;
DECLARE V_IND_LEGENDA DECIMAL(1);
DECLARE V_VARIANTE ANCHOR DATA TYPE TO DMTLDBR.TB_DIM_PRODVARIANTE.ID_VARIANTE;
DECLARE V_VAL_PERDA ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_VENDASDIARIO.VAL_TONLIQUIDO;
DECLARE V_VAL_DESOVA ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_VENDASDIARIO.VAL_TONLIQUIDO;
DECLARE V_VAL_UHT ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_VENDASDIARIO.VAL_TONLIQUIDO;
DECLARE V_VAL_SUCO ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_VENDASDIARIO.VAL_TONLIQUIDO;
DECLARE V_VAL_REQ ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_VENDASDIARIO.VAL_TONLIQUIDO;
DECLARE V_FAT_UHT ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_VENDASDIARIO.VAL_FAT357;
DECLARE V_FAT_REQ ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_VENDASDIARIO.VAL_FAT357;
DECLARE V_ID_DIA_INI ANCHOR DATA TYPE TO DMTLDBR.TB_DIM_DIADIA.ID_DIA;
DECLARE V_ID_DIA_FIM ANCHOR DATA TYPE TO DMTLDBR.TB_DIM_DIADIA.ID_DIA;
DECLARE FLAG_DIA_UTIL BOOLEAN;
DECLARE V_SUM_VAL_TONVNEMA_CAL ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_DASH_CALENDARIO.VAL_TONVNEMA_CAL;
DECLARE V_SUM_VAL_FAT357 ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_VENDASDIARIO.VAL_FAT357;
DECLARE V_SUM_VAL_ABATIMENTOREPORTADO ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_VENDASDIARIO.VAL_ABATIMENTOREPORTADO;
DECLARE V_SUM_VAL_ICMSZFMREPORTADO ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_VENDASDIARIO.VAL_ICMSZFMREPORTADO;
DECLARE V_PROC ANCHOR DATA TYPE TO DMTLDBR.TB_TMP_LOG_EXECUTION_PROC.SYNCPOINT_PROC;
SET V_PROC = 'SP_DASH_CALENDARIO';
-- =========================================================================================================
-- P R O C P R O C U R A _ D I A _ U T I L _ P O S T _ D I A 1
--
-- OBTEM O PRIMEIRO DIA ÚTIL DO MÊS (QUE NÃO SEJA DOMINGO NEM FERIADO)
--
-- =========================================================================================================
BEGIN
DECLARE PROCEDURE PROCURA_DIA_UTIL_POST_DIA1(IN P_ID_MES INTEGER)
BEGIN
DECLARE V_ACHOU DECIMAL(1) DEFAULT 0;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION, SQLWARNING, NOT FOUND BEGIN END;
SET V_ID_DIA = NULL;
L1: LOOP -- (LP01)
BEGIN -- (BE02.)
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' BEGIN END;
SELECT MIN(ID_DIA) INTO V_ID_DIA
FROM DMTLDBR.TB_DIM_DIADIA
WHERE ID_MES = P_ID_MES
AND ID_DIASEMANA <> 1 -- DOMINGO
AND FLG_HOLIDAY = 0;
END; -- (BE02.)
IF SQLSTATE = '00000' THEN
LEAVE L1;
--SET V_ACHOU = 1;
END IF;
END LOOP L1; -- (LP01.)
END;
END;
CALL DMTLDBR.PROCURA_DIA_UTIL_POST_DIA1(201909);
END
A Compound SQL (compiled) statement requires strict order of declarations / statements inside.
For example:
--#SET TERMINATOR #
CREATE OR REPLACE PROCEDURE TEST_LOCAL(P_I INT)
BEGIN
-- SQL-variable-declarations
DECLARE L_I INT;
-- DECLARE-CURSOR-statements
DECLARE C1 CURSOR FOR VALUES 1;
-- procedure-declaration
DECLARE PROCEDURE TEST_LOCAL_NESTED(P_J INT) BEGIN END;
-- handler-declarations
DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN END;
-- SQL-procedure-statements
CALL TEST_LOCAL_NESTED(P_I);
END#
Briefly for each BEGIN END block:
1-st: all SQL-variable-declarations
2-nd: all DECLARE-CURSOR-statements
3-rd: all procedure-declaration
4-th: all handler-declarations
All SQL-procedure-statements come afterwards only. These statements may contain nested BEGIN END blocks, where the same strict declaration / statement rules apply.
You have more than one mistake in the code shown in the question.
You are using a local procedure, that is the name for a procedure declared inside another procedure.
Local-Procedures work fine when used correctly.
Some suggestions to allow successful compilation:
the declare procedure must appear before any executable statements or new block in the calling procedure.
Move the statement SET V_PROC = 'SP_DASH_CALENDARIO' so that it appears
before the CALL to the local procedure (or anywhere within the main procedure block AFTER
all declarations (including after declaring the local procedure).
Additionally, remove the BEGIN (and matching END) on the line before DECLARE PROCEDURE.
You want all the declares to appear before any executable statement or new begin-end block.
the local procedure name must be unqualified both on the DECLARE and on the CALL
but you are using a qualifier on your CALL statement which will prevent Db2 from finding the local procedure.
The last part of your procedure will then look something like below:
...snip...
DECLARE V_SUM_VAL_ICMSZFMREPORTADO ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_VENDASDIARIO.VAL_ICMSZFMREPORTADO;
DECLARE V_PROC ANCHOR DATA TYPE TO DMTLDBR.TB_TMP_LOG_EXECUTION_PROC.SYNCPOINT_PROC;
-- =========================================================================================================
-- P R O C P R O C U R A _ D I A _ U T I L _ P O S T _ D I A 1
--
-- OBTEM O PRIMEIRO DIA ÚTIL DO MÊS (QUE NÃO SEJA DOMINGO NEM FERIADO)
--
-- =========================================================================================================
DECLARE PROCEDURE PROCURA_DIA_UTIL_POST_DIA1(IN P_ID_MES INTEGER)
BEGIN
DECLARE V_ACHOU DECIMAL(1) DEFAULT 0;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION, SQLWARNING, NOT FOUND BEGIN END;
SET V_ID_DIA = NULL;
L1: LOOP -- (LP01)
BEGIN -- (BE02.)
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' BEGIN END;
SELECT MIN(ID_DIA) INTO V_ID_DIA
FROM DMTLDBR.TB_DIM_DIADIA
WHERE ID_MES = P_ID_MES
AND ID_DIASEMANA <> 1 -- DOMINGO
AND FLG_HOLIDAY = 0;
END; -- (BE02.)
IF SQLSTATE = '00000' THEN
LEAVE L1;
--SET V_ACHOU = 1;
END IF;
END LOOP L1; -- (LP01.)
END;
SET V_PROC = 'SP_DASH_CALENDARIO';
CALL PROCURA_DIA_UTIL_POST_DIA1(201909);
END#

Why does using new in a Dafny function give an error?

I am wondering why I am getting an error for the following program:
class KV
{
var key : int;
var value : int;
constructor (k: int, v: int) modifies this
{
this.key := k;
this.value := v;
}
}
function foo () : KV
{
new KV(0,0)
}
I got: invalid UnaryExpression when I ran this.
In Dafny functions are pure. They can depend on the heap, by giving a reads clause. But they cannot have side effects - they cannot modify the heap. Since your function foo has zero arguments and no reads clause, it must return the same value each time it is called. The memory allocation operator new gives a different value each time it is called, so can't be used in a function.
It is also important to note that Dafny functions are ghost by default. They are not executable at runtime. Rather they are used during the verification phase of compilation. If you want a non ghost function you must write function method instead of function.
You can use new inside a method. Methods are imperative procedures and do not need to be pure.
class KV
{
var key : int;
var value : int;
constructor (k: int, v: int) modifies this
{
this.key := k;
this.value := v;
}
}
method foo () returns (kv:KV)
{
kv := new KV(0,0);
}

Nested constants of nested structured types are unsupported?

Despite of what Delphi reference says
structured types can contain other structured types; a type can have unlimited levels of structuring
with notable exception what structured typed constants
cannot contain file-type values at any level
I discovered what I cannot use record constant as an element of array constant of the same type.
Testcase
type
MyRecord = record MyField: Integer end;
const
Typical: array[0..1] of MyRecord = ((MyField: 0), (MyField: 1));
{ now I tried to achieve more clarity by declaring a specific constant }
Zero: MyRecord = (MyField: 0);
{ and compiler refused to accept that }
Bad: array[0..1] of MyRecord = (Zero, (MyField: 1)); { E2029 '(' expected but identifier 'Zero' found }
I tested this code with several Borland compilers, all of them exhibited the same behaviour. UPD: also the same for FPC, but not for GPC(!).
Question(s)
What is going on here? Am I correct with "Nested constants of nested structured types are unsupported" conclusion in the question title? Any more analysis of an issue?
It appears that this isn't possible, the underlying cause is that ZeroRec isn't truly a constant, it is more like an initialised static variable.
If {$WRITEABLECONST ON} is specified, then it can be trivially changed. Even with $WRITEABLECONST OFF, it can be changed by some creative type casting (tested in XE2):
program Project3;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils;
type
MyRecord = record MyField: Integer end;
PMyRecord = ^MyRecord;
const
Typical: array[0..1] of MyRecord = ((MyField: 0), (MyField: 1));
{ now I tried to achieve more clarity by declaring a specific constant }
ZeroRec: MyRecord = (MyField: 0);
{ and compiler refused to accept that }
// Bad: array[0..1] of MyRecord = ((MyField: Zero), (MyField: 1)); { E2029 '(' expected but identifier 'Zero' found }
begin
try
{ TODO -oUser -cConsole Main : Insert code here }
WriteLn(ZeroRec.MyField);
PMyRecord(#ZeroRec)^.MyField := 2;
WriteLn(ZeroRec.MyField);
readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
This will output
0
2
The behaviour is also evident with simple types,
Zero = 0;
ZeroRec: MyRecord = (MyField: Zero);
compiles as expected, however
Zero : Integer = 0;
ZeroRec: MyRecord = (MyField: Zero);
gives [DCC Error] Project3.dpr(19): E2026 Constant expression expected
What you are declaring is called a Typed Constant. And in this specific case it is an Array Constant. The documentation states (emphasis mine):
To declare an array constant, enclose the values of the array's elements, separated by commas, in parentheses at the end of the declaration. These values must be represented by constant expressions.
The code that the compiler objects to is where you attempt to use a typed constant where only a constant expression is allowed.
This is one of the most frustrating areas of the Delphi language because the language forces you to repeat yourself.

method call of a generic list with RTTI

I don't know how to do this:
Having this objects:
TMyObject = class;
TMyList<T: TMyObject> = class(TList<T>)
public
function Execute(aParam1, aParam2:string):boolean;
end;
TMyOtherObject = class(TMyObject)
TMyOtherList = class(TMyList<TMyOtherObject>);
How can I execute the "execute" function via rtti if I receive
a TMyOtherList object in a function param as an TObject?
Thanks.
Don't bother with RTTI, just use a cast:
(aObject as TMyOtherList).Execute(param1, param2);
If casting is not an option then use an interface.

Resources