If I have a Function Block with an explicitly defined FB_Init method, I can't seem to use the Retain keyword, as I get a C0138: No matching FB_init method found for instantiation of POU error, for example:
FUNCTION_BLOCK POU1
VAR
_val: INT;
END_VAR
METHOD FB_Init : BOOL
VAR_INPUT
bInitRetains : BOOL;
bInCopyCode : BOOL;
val: INT;
END_VAR
THIS^._val := val;
PROGRAM SR_Main
VAR RETAIN
p1: POU1(val := 10); // C0138: No matching FB_init method found for instantiation of POU1
END_VAR
The project seems to build without error, until I try to run a simulation that fails with the above error. I am using Machine Expert 1.2.3 (CODESYS 3.5.12 I believe)
How do I retain Function Blocks with FB_Init methods?
PS. The only way I found so far, is to manually write the RETAIN keyword on every VAR type inside the Function Block (VAR, VAR_OUTPUT), but then I'll have to have 2 separate version of this object (unretained, and retained, like POU1 and POU1_RETAINED for example), not to mention that, that will not work with PERSISTENT.
The code from Guiorgy runs as intended on both Twincat 3 and Codesys 3.5.
The error, which occurs when running the example using Machine Expert, must be a specific Schneider issue.
Related
There is a problem when u define an enum in a method.
I was trying to do this:
VAR
enumA:(A,B,C);
END_VAR
and there is the compiler reaction when I used this in TwinCAT3 Shell (TcXaeShell).
any help would be appreciated.
You can only use global enumerations in methods. It's one of the limitations with local enumerations.
https://alltwincat.com/2021/11/16/local-enumerations/
You should first define variable type as enumeration in DUT
TYPE MyEnum:
(A, B, C)
END_TYPE
Then in a program you can declare variable of that type
VAR
enum: MyEnum;
END_VAR
Inside the program if you want to compare it.
IF enum = MyEnum.C THEN
// Do something
END_IF;
I’ve run into this issue before. You must declare the local enumeration in the variables section of the function block. Then you can use it in the methods of the function block.
I'm doing the Delphi track at exercism, and following how Delphi generates code for a form, answered one of the basic questions like this:
unit uLeap;
interface
type
TSYear = class
public
{ public declarations here }
function isLeap(y: integer): boolean;
end;
var
TYear: TSYear;
implementation
function TSYear.isLeap(y: integer): boolean;
begin
result := ((y mod 4) = 0) and (((y mod 400) = 0) or ((y mod 100) <> 0));
end;
end.
the code compiles without a single complaint, I can run it step by step, and the "isLeap" function is called from another unit several times this way:
procedure YearTest.year_divisible_by_4_not_divisible_by_100_leap_year;
begin
assert.IsTrue(TYear.IsLeap(1996), 'Expected ''true'', 1996 is a leap year.');
end;
...
I've never explicitly created the instance of the class, but it seems as if Delphi is doing it somewhere, maybe when declaring TYear? Is that a valid way?
Despite passing all the tests the code was rejected because it isn't done the conventional way. I'll surely end up doing it differently to have it accepted, but, besides the bad naming, why is this working? Would this code cause problems somewhere I can't see in this simple example?
I've never explicitly created the instance of the class, but it seems as if Delphi is doing it somewhere, maybe when declaring TYear?
No, Delphi is NOT automatically creating an instance of you. When you declare a variable of a class type, it is simply a pointer variable that can be made to point at a valid instance. But you must always create this instance yourself, and save the pointer in the variable:
SYear := TSYear.Create; // create a `TSYear` object and save its address in `SYear`
Is that a valid way?
No.
[W]hy is this working?
Because you are lucky: The isLeap function doesn't access any fields on the class instance.
Would this code cause problems somewhere I can't see in this simple example?
If the function had been using any fields in the class instance, you would have ended up with an AV if lucky and memory corruption if unlucky.
The solution is either to create an instance and use it:
SYear := TSYear.Create;
try
ShowMessage(BoolToStr(SYear.IsLeap(2000), True));
finally
SYear.Free;
end;
Or, since you clearly don't need any instance variables to determine if a year is a leap year or not, it is better to make this a class method:
type
TSYear = class
public
class function IsLeap(AYear: Integer): Boolean; static;
end;
This way, it can be called without any class instance: TSYear.IsLeap(2000). Notice that TSYear is the class (type) name, not a variable of this type.
Please see the documentation for a great conceptual introduction to all these concepts.
Last year the solution to a problem was to make my instance variables atomics to ensure other tasks would see their changes. (While loop in a method gets stuck. Adding an assignment of a field to itself fixes the issue)
This year I'm replacing my constructors with initializers. (https://chapel-lang.org/docs/master/language/evolution.html#readme-evolution-initializers-replace-constructors) Unfortunately, I don't know how to initialize atomic instance variables. This code doesn't work:
class FakeSemaphore {
var tokens : atomic int;
proc init(initTokens : int) {
this.tokens.write(initTokens);
}
}
This results in the following in chapel 1.18:
$ chpl FakeSemaphore.chpl
FakeSemaphore.chpl:4: In initializer:
FakeSemaphore.chpl:5: error: field "tokens" used before it is initialized
How should I be initializing my atomic instance variables?
The short answer is that you should insert a call to this.complete() prior to your call to this.tokens.write(), as shown here (Try It Online):
class FakeSemaphore {
var tokens : atomic int;
proc init(initTokens : int) {
this.complete();
this.tokens.write(initTokens);
}
}
var s = new owned FakeSemaphore(10);
writeln(s);
In more detail:
Chapel initializers can be thought of as having multiple phases. Initially, none of the fields are initialized and the object and its fields cannot be used until they are. Fields can either be explicitly initialized via the assignment operator (=) or implicitly initialized by the compiler.
The built-in call this.complete() is used to indicate that the object has been initialized and is ready for use. Upon encountering it, the compiler will take care of initializing any remaining fields that the user did not. After the call to this.complete(), the object is ready for use.
In this case, even though you're logically using the method call this.tokens.write(initTokens) to initialize this.tokens, Chapel doesn't recognize it as a field initialization since it isn't using the assignment operator. Moreover, since it's a method call on the field, it is only permitted once the object has been initialized (i.e., after the call to this.complete()).
Note that Chapel has a long-standing intention (captured in issue #5037 on our GitHub issues page) to support direct initialization of atomic variables. Once this is supported, you should just be able to write:
class FakeSemaphore {
var tokens : atomic int;
proc init(initTokens: int) {
this.tokens = initTokens;
}
}
I expect this feature to become available in 2019. Also note a related request to be able to directly assign atomic variables rather than being forced to use .write() in issue #8847
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 7 years ago.
Improve this question
I currently have the following code;
interface
{...}
type
TMyRecord = record
List : TShellList;
Tree : TShellTree;
Image : TImage;
end;
TSDIAppForm = class(TForm)
{ Published declarations }
private
function GetChildren(Sheet : TTabSheet) : TMyRecord;
public
{ Public declarations }
end;
As I understand it this means that TMyRecord is a global type visible to the whole program. The type only needs to be visible within the class, although objects of the type do need to be passed and returned as parameters to between "private" functions/procedures of the class. How can I do that? I can't declare the type under the "private" part of the class interface, and if I declare it in the implements then I don't believe it is visible to be used in the interface function prototypes. Also, I think implements/interface relate more to visibility within the unit than the class. Do I need to declare theGetChildren() function in some other way?
As noted in other answers, in versions of Delphi that support nested types you can simply declare the type within the required scope and visibility.
For older versions of Delphi you can achieve a similar outcome by using an untyped var parameter to avoid having to reference the 'private type' in the interface section of your unit:
TSDIAppForm = class(TForm)
..
procedure GetChildren(Sheet : TTabSheet; var aRecord);
..
end;
For convenience and declarative type enforcement in the implementation of the method you can use an absolute declaration to create a local variable to act as placeholder for the untyped parameter:
procedure TSDIAppForm.GetChildren( Sheet : TTabSheet;
var aRecord);
var
result: TMyRecord absolute aRecord;
begin
result.List := ...;
// etc
end;
In this case, since the function has no direct return value and uses the var param in a directly analagous way you might choose to use the name result, as illustrated. Or of course you can use any other name for the local variable you prefer.
In use, you would simply call this method as normal with an appropriate variable in the var param:
var
myRec: TMyRecord;
begin
..
sdiForm.GetChildren(someSheet, myRec);
..
end;
In this way, you can keep a type which is an implementation detail truly confined to the implementation section of your unit.
NOTE: This technique can also be useful in situations where typed var parameters might otherwise cause the compiler to complain about 'formal var parameter types not matching'.
You should of course always consider carefully whether they are the right approach. Not least because whenever you use untyped parameters of course you take on a greater responsibility for ensuring type safety in your code. The potential for abuse should be obvious, but they sometimes offer advantages as well (as in this case, removing entirely a type from the interface section that is arguably most properly entirely confined to the implementation section).
They can also be a useful tool to keep in mind if you create code that you might wish to make available to users of older versions of Delphi where private types etc are not available.
Per Uwe, just declare in private section. Tested in XE8. The following works
TSDIAppForm = class(TForm)
private
type
TMyRecord = record
List : TShellList;
Tree : TShellTree;
Image : TImage;
end;
function GetChildren(Sheet : TTabSheet) : TMyRecord;
public
{ Public declarations }
end;
Please take a look at the following Free Pascal program.
type
IMyInterface = interface
end;
TMyClass = class(TInterfacedObject, IMyInterface)
end;
var
MyInstance: TMyClass;
procedure DoSomething(MyParameter: IMyInterface);
begin
end;
begin
MyInstance := TMyClass.Create;
DoSomething(MyInstance);
MyInstance.Free;
end.
The program crashes during the access to the destructor with a SIGSEGV when started from within the IDE (compiled with debug information). Why? It works when I use TInterfacedObject, TObject, or TMyClass as parameter type. It even works when I use the const keyword for said parameter. Can anyone explain this behavior? With a quick sideways glance to Java I would expect this to work.
Compiled with FreePascalCompiler 2.6.4, executed under Windows 7.
I cannot speak for FPC, but with Delphi it is a bad idea to mix interfaces and objects. In this case you have two solutions:
declare MyInstance as IMyInterface and remove the call to Free.
inherit TMyClass from TInterfacedPersistent.
To clarify what is actually happening: Creating the TMyClass instance and assigning it to MyInstance will keep the reference count to 0. When you pass it to DoSomething a cast to IMyInterface takes place and the reference counter increases. When DoSomething ends the reference counter decreases to 0 and the instance is freed. The following call to Free will free an already freed instance.
DoSomething expect a IMyInterface
when you pass MyInstance , it's make a counter control, so when the method DoSomething finish, MyInstance has a counter decrement.
the TMyClass is a TInterfacedObject, so when the counter = 0, then Object will be freed, so you don't need to call MyInstance.Free;
you can do:
DoSomething(TMyClass.Create);
Your Object uses Reference Counting, to free it you must decrement the reference count. An alternative is to use what's called CORBA interfaces.
In FPC object pascal mode a CORBA interface is a pure interface which does not derivates from IUnknown (in opposite to COM interfaces). If you add the compiler directive:
{$INTERFACES CORBA}
then you'll be able to use the .Free method, just like with any other TObject instance. Note that the name can be confusing since CORBA is a full cross-language specification (IDL), but here corba just means "not COM".
online reference:
http://www.freepascal.org/docs-html/ref/refse44.html#x98-1080007.6