method call of a generic list with RTTI - delphi

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.

Related

How to write equivalent of Delphi "is" and "as" in C++ Builder?

I want to write a function (or even an operator, if possible) that is doing something similar to Delphi's "is".
Delphi example:
if Sender is TMenuItem then
TMenuItem(Sender)->Enabled = false;
So, in C++ Builder this would be something like:
bool Is(*p1, *p2)
{
p = dynamic_cast<p1*>(p2); //here we typecast TObject to TMenuItem
if (!!p)
{
return true;
}
else return false;
}
How can I make the function accept any kind of objects for p1, p2?
Q: How can I make the function accept any kind of objects for p1, p2?
A: Use a template, like this:
template<typename T, typename PtrType>
bool IsA(PtrType *ptr)
{
return dynamic_cast<T*>(ptr) != nullptr;
}
Use the templated function like this:
A* obj = new C();
if (IsA<C>(obj))
{
std::cout << "obj is of type C";
}
With that said, I advise you to avoid creating such a function for 2 reasons:
You could just use the dynamic_cast eveywhere, it's more idiomatic and shows you the cost you are paying to do this kind of check
Checking for the specific type is in general a sign of a flawed design. There are some cases when it's needed, but that's rare, and in general my personal opinion is that it shouldn't be condoned in general, which such a function would do.

F# inherit interface

I have the following class in F# that inherits Microsoft.AspNet.Identity.IIdentityValidator interface:
type MyValidation() =
inherit IIdentityValidator<string> with
member x.ValidateAsync (value:string) : Task<IdentityResult> =
.....
I am getting this error:
This 'inherit' declaration specifies the inherited type but no arguments. Consider supplying arguments, e.g. 'inherit BaseType(args)'.
Why and how do I fix it?
The keyword inherit is just for derived classes. You need to use interface:
type MyValidation() =
interface IIdentityValidator<string> with
member x.ValidateAsync (value:string) : Task<IdentityResult> =
...

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.

Avoid using "mutable" variable to call a method with a byref (out in C#) parameter?

So I have this class in C#:
public class Foo : IFoo {
public bool TryConnect(out Status status) {
...
}
}
And I want to consume it with F#.
Unfortunately I had to use some hackery such as:
type FooService (foo : IFoo) =
member x.Execute() =
let mutable status = Unchecked.defaultof< ^Status>
foo.TryConnect(&status) |> ignore
(...do something with status...)
Is there a way to not use "mutable" here? In the end, I'm not actually using the first initialization value at all.
(I'm using F# 2.0, but if you have hints that only apply to F# 3.0, I'll be happy to hear them.)
Thanks
out params are automatically tuplized. So, you can do:
let res, status = foo.TryConnect()
For more info, see Passing by Reference on MSDN.

Pass class to record

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.

Resources