Why does setting a Char variable to nil cause compilation to fail? - pascal

In my case below I don't want c to be assigned to anything until the first character of the file is read.
I tried setting the Char variable c to nil (c := nil;) but compilation fails. I tried an empty string like below, and still doesn't work.
It works when I set it to an empty space, but it seems peculiar that I have to do that.
Is there any way to initialize a Char to a null like value as you can do in other languages?
program CSVToMarkdown;
{$mode objfpc}{$H+}{$J-}
uses
Sysutils;
var
f: File of Char;
c: Char;
begin
Assign(f, 'test.csv');
Reset(f);
c := '';
while not Eof(f) do
begin
Read(f, c);
Write(c);
end;
Close(f);
ReadLn;
end.

NIL is a value for pointers, or reference types (interfaces,class, dyn arrays) in general.
Non reference types don't have a NIL value, the type char can take values from #0 to #255, and all are valid, though sometimes when interfacing to other languages #0 is interpreted as end of string.
If you mean nullable types like in Java or .NET, there is no default support for them as they have the disadvantage of the type becoming larger than need be (iow becoming a pseudo record with added NULL boolean).
There are some generics based solutions that try to implement nullable types, but I haven't used them, and they are not part of the standard distribution.

Related

Which string copying method is the faster in Delphi?

I work in Delphi XE2 and I have to make a complicated function that sometimes copies longer parts of strings and sometimes only just characters. It depends on the content of the source string. So the question is that which example method is faster?
Len := Length(Str);
SetLength(Result, Len);
for I := 1 to Len do Result[I] := Str[I];
Len := Length(Str);
SetLength(Result, Len);
Move(Str[1], Result[1], Len * SizeOf(Char));
And I would be also curious how big is the difference in running time.
The Move() alternative - even if Move() was written naively as a byte-by-byte loop (which it is not in the RTL, despite much room for optimization, which we might get soon(tm)) - would be faster, because for every indexed write to a string, the compiler inserts a call to System._UniqueStringU().
To copy a part (if contiguous) of a string into a new string, I would probably use either System.Copy() or System.SetString() instead.
However, if performance matters, my intuition tells me that this part would probably not be the one worth optimizing, but rather to reduce string usage and copying parts of them as new strings. In .NET, that was the reason why they implemented Span<T>, which basically is a length restricted pointer. When dealing with things like string parsing, using such an approach boosts performance way more than optimizing the copying itself.
Bonus: If you write your loop like this, you omit the _UniqueStringU() call, because the SetLength() before already assured that Result is a string with RefCount = 1:
Len := Length(Str);
SetLength(Result, Len);
for I := 1 to Len do PChar(Pointer(Result))[I-1] := Str[I];
I am using a cast to Pointer first to avoid the _UStrToPWChar() call the compiler inserts when doing a string to PChar cast.

How to declare data type ENUM in Yaskawa MotionWorks IEC 3?

I'm trying to add my own enum in MotionWorks.
After creation of new data type the only available types are ARRAY,STRING,STRUCT.
Writing the following code:
TYPE SimulationType:
(
Passing := 0,
Random := 1,
Failing := 2
) INT := 0;
END_TYPE
does not compile.
Yaskawa seem to be complying to ENUM (according to this list) but I can't figure out how to declare it.
Edit:
I can do the following:
TYPE
ResultType:(Pass, Random, Fail);
END_TYPE
But it doesn't seem to create an enum, as I can't access it's value. I can access it like a structure.
Edit 2:
If I declare:
TYPE
ResultType:(Pass, Random, Fail);
END_TYPE
And set variable
ExpectedResultType : ResultType;
Then in the code I try to use:
IF ExpectedResultType = ResultType.Pass THEN
Done := TRUE;
END_IF;
It compiles, but will not run.
Trying to use this code will not compile:
CASE ExpectedResultType OF
ResultType.Pass:
Done := TRUE;
Error := FALSE;
ResultType.Random:
Done := TRUE;
ResultType.Fail:
Error := TRUE;
Done := FALSE;
END_CASE;
Enums in MotionWorks are declared in data types as this example:
TYPE
MyEnum:(Zero,One,Two,Three);
END_TYPE
ENUMs in MotionWorks can't be assigned a value. First enum will always be equal to 0 (zero), second one to 1 (one), and so on.
Then enums can be used in IF .. END_IF statements like this:
I'll call my variable "i". The variable must be declared as INT. Any other type will not work.
In the code use it like this:
IF i = MyEnum#Zero THEN
(* do some work *)
ELSIF i = MyEnum#One THEN
(* do some other work *)
END_IF
ENUMs can't be used in CASE statements in MotionWorks.
This what I have for Schneider which is IEC61131 so it should be the same
TYPE E_HomeLimitSwitch:
(
ePositiveDirectionRisingEdge := 0,
eNegativeDirectionRisingEdge := 1,
ePositiveDirectionFallingEdge := 2,
eNegativeDirectionFallingEdge := 3
);
END_TYPE
I don't think you INT:=0 should be there.
You can only set the default value to one of your local enum members. Not to other values or even a number as you tried.
Try this instead in line 6:
) INT := Passing;
unlike Codesys, Yaskawa's MotionWorksIEC does not fully support enumerations. In ST language enum usage is quite popular in CASE statements but MotionWorksIEC does not support enum use in case statements.
But, you still can define enums as shown below.
TYPE
PackMLState:(Starting,Starting,Aborting,Aborted,Helding,Held,Etc);
END_TYPE
You can use the enum type as;
IF machineState = PackMLState#Starting THEN
;;
END_IF
Comparing Codesys and MotionWorksIEC (Which is basically Phoenix Contact, KW Software Multiprog), there are some differences. For clarification, the lack of enum use in Cases doesn't make Multiprog an inferior IDE.

Seg fault/error 216 when using Fillchar()

After I added Fillchar() looking for do C's memset() equivalent in pascal the program give a runtime error 216.
Here's my code (if I remove FillChar() it works fine):
function NewFoo(name : string) : ptrfoo;
var sym : ptrfoo;
begin
new(sym);
FillChar(sym, SizeOf(foo), #0);
sym^.name := name;
NewFoo := sym;
end;
foo is a record and fooptr a pointer to it defined as type fooptr = ^foo;.
How do I fix this?
Fillchar takes an untyped parameter, not a pointer. As it is you are overwriting the pointer itself (and memory well beyond it) with zeroes. You want to dereference the pointer to use it with Fillchar:
FillChar(sym^, SizeOf(foo), #0);
Untyped parameters are the parameters of the form const foo, var foo, out foo with seemingly no type attached to them. They cannot be assigned or used directly, but you can dereference them and get a pointer to them. Basically, they are syntactic sugar to be able to pass records and other variables around as if they were blobs of data without having to take a pointer to them C-style from the calling end (in reality it's a bit more complex, but that's the gist of it).

How to ignore fields with sscanf (%* is rejected)

I wish to ignore a particular field whilst processing a string with sscanf.
Man page for sscanf says
An optional '*' assignment-suppression character: scanf() reads input as directed by the conversion specification, but discards the input. No corresponding pointer argument is required, and this specification is not included in the count of successful assignments returned by scanf().
Attempting to use this in Golang, to ignore the 3rd field:
if c, err := fmt.Sscanf(str, " %s %d %*d %d ", &iface.Name, &iface.BTx, &iface.BytesRx); err != nil || c != 3 {
compiles OK, but at runtime err is set to:
bad verb %* for integer
Golang doco doesn't specifically mention the %* conversion specification, but it does say,
Package fmt implements formatted I/O with functions analogous to C's printf and scanf.
It doesn't indicate that %* is not implemented, so... Am I doing it wrong? Or has it just been quietly omitted? ...but then, why does it compile?
To the best of my knowledge there is no such verb (as the format specifiers are called in the fmt package) for this task. What you can do however, is specifying some verb and ignoring its value. This is not particularly memory friendly, though. Ideally this would work:
fmt.Scan(&a, _, &b)
Sadly, it doesn't. So your next best option would be to declare the variables and ignore the one
you don't want:
var a,b,c int
fmt.Scanf("%d %v %d", &a, &b, &c)
fmt.Println(a,c)
%v would read a space separated token. Depending on what you're scanning on, you may fast forward the
stream to the position you need to scan on. See this answer
for details on seeking in buffers. If you're using stdio or you don't know which length your input may
have, you seem to be out of luck here.
It doesn't indicate that %* is not implemented, so... Am I doing it
wrong? Or has it just been quietly omitted? ...but then, why does it
compile?
It compiles because for the compiler a format string is just a string like any other. The content of that string is evaluated at run time by functions of the fmt package. Some C compilers may check format strings
for correctness, but this is a feature, not the norm. With go, the go vet command will try to warn you about format string errors with mismatched arguments.
Edit:
For the special case of needing to parse a row of integers and just caring for some of them, you
can use fmt.Scan in combination with a slice of integers. The following example reads 3 integers
from stdin and stores them in the slice named vals:
ints := make([]interface{}, 3)
vals := make([]int, len(ints))
for i, _ := range ints {
ints[i] = interface{}(&vals[i])
}
fmt.Scan(ints...)
fmt.Println(vals)
This is probably shorter than the conventional split/trim/strconv chain. It makes a slice of pointers
which each points to a value in vals. fmt.Scan then fills these pointers. With this you can even
ignore most of the values by assigning the same pointer over and over for the values you don't want:
ignored := 0
for i, _ := range ints {
if(i == 0 || i == 2) {
ints[i] = interface{}(&vals[i])
} else {
ints[i] = interface{}(&ignored)
}
}
The example above would assign the address of ignore to all values except the first and the second, thus
effectively ignoring them by overwriting.

ResourceString VS Const for string literals

I have a couple of thousands string literals in a Delphi application. They have been isolated in a separate file and used for localization in the past.
Now I don't need localization any more.
Is there any performance penalty in using resourcestring compared to plain constants.
Should I change those to CONST instead?
The const string makes a call to _UStrLAsg and the resource string ends up in LoadResString.
Since the question is about speed there is nothing like doing a test.
resourcestring
str2 = 'str2';
const
str1 = 'str1';
function ConstStr1: string;
begin
result := str1;
end;
function ReceStr1: string;
begin
result := str2;
end;
function ConstStr2: string;
begin
result := str1;
end;
function ReceStr2: string;
begin
result := str2;
end;
procedure Test;
var
s1, s2, s3, s4: string;
begin
s1 := ConstStr1;
s2 := ReceStr1;
s3 := ConstStr2;
s4 := ReceStr2;
end;
For the first time I used AQTime added in DelphiXE to profile this code and here is the result. The time column show Machine Cycles.
I might have done a lot of rookie mistakes profiling this but as I see it there is a difference between const and resourcestring. If the difference is noticeable for a user depends on what you do with the string. In a loop with many iterations it can matter but used to display information to the users, not so much.
Since they are stored in a single file which presumably does little else (well done!), there's no reason not to try it out. I predict it won't make any discernible difference to performance, but I guess it depends on what else you are doing in your app.
Resource strings do incur overhead.
Compared to displaying such a string, or writing it to a file or database, the overhead is not much.
On the other hand it is just a switch from the resourcestring to const keyword (and back if you ever consider to to localization again).

Resources