Recent

Author Topic: Nullable and Immutable types  (Read 1956 times)

lainz

  • Hero Member
  • *****
  • Posts: 4468
    • https://lainz.github.io/
Nullable and Immutable types
« on: January 02, 2021, 11:17:21 pm »
Hi, several programming languages supports one time assignable constants (say to store the result of a function call) and as well nullable types.

In the wiki is described how to create a nullable type.
https://wiki.freepascal.org/Nullable_types

How this example can be extended to support one time assignments?

The assignment can be prevented at compile time in some way, or it will work only at runtime?

Peter H

  • Sr. Member
  • ****
  • Posts: 272
Re: Nullable and Immutable types
« Reply #1 on: January 03, 2021, 12:00:13 am »
So far I see here: https://wiki.freepascal.org/How_to_use_nullable_types the nullable types must be explicitely programmatically cleared before first usage.
This is because there is no constructor called automatically in pascal.
So you could add code to the nullable type that assignment is only possible if clear.
(Im unsure how to prevent multiple clearing and reassignement)
I think this must happen at runtime because the compiler can impossibly know at compile time if an assignment is the first assignment, if a program has multiple conditional paths.

« Last Edit: January 03, 2021, 12:05:07 am by Peter H »

lainz

  • Hero Member
  • *****
  • Posts: 4468
    • https://lainz.github.io/
Re: Nullable and Immutable types
« Reply #2 on: January 03, 2021, 12:03:18 am »
I see only at runtime... ok, better than nothing.

Maybe adding another boolean, but again that will be cleared with the clear option that's needed to initialize it...  ::)

Peter H

  • Sr. Member
  • ****
  • Posts: 272
Re: Nullable and Immutable types
« Reply #3 on: January 03, 2021, 12:39:08 am »
Just an idea, I have not done it, but I think it is possible:
This could be a solution: https://wiki.freepascal.org/FPC_New_Features_3.2.0#Management_operators_for_record_types

Using this, the "Clear" Flag can be initialized at time of variable definition.
Programmatical clearing is not necessary then and if the Clear flag is private and Clear procedure deleted,  impossible.

Kays

  • Hero Member
  • *****
  • Posts: 575
  • Whasup!?
    • KaiBurghardt.de
Re: Nullable and Immutable types
« Reply #4 on: January 03, 2021, 12:50:21 am »
[…] https://wiki.freepascal.org/How_to_use_nullable_types the nullable types must be explicitely programmatically cleared before first usage. […]
Well, de facto the FHasValue of the nullable types is zeroed, so virtually “initialized” with false, thus it isn’t actually required, but nevertheless clean programming.

[…] This is because there is no constructor called automatically in pascal. […]
Also, that page was written over 2 years ago. Meanwhile, FPC 3.2.0 has been released, so (not using classes) one could use management operators for extended records now. This will eliminate the requirement to “manually” invoke some initialization routine when a variable enters scope.

I see only at runtime... ok, better than nothing. […]
Well, it’s just in trunk for now, but you can probably build something with generics with constants parameters.
Yours Sincerely
Kai Burghardt

Peter H

  • Sr. Member
  • ****
  • Posts: 272
Re: Nullable and Immutable types
« Reply #5 on: January 03, 2021, 12:59:53 am »
Quote
Well, de facto the FHasValue of the nullable types is zeroed, so virtually “initialized” with false, thus it isn’t actually required, but nevertheless clean programming.

I do not see where "FHasvalue" is zeroed in this example. If the Nullable record is instantiated as local variable, then it occupies random uninitialized memory and there must be some code to initialize it.

I do not know, if global static memory is zeroed, but this might be different on different OS, or the debugger or linker or loader could do it or not do it, so I would not rely on this.
« Last Edit: January 03, 2021, 01:05:35 am by Peter H »

jamie

  • Hero Member
  • *****
  • Posts: 6130
Re: Nullable and Immutable types
« Reply #6 on: January 03, 2021, 01:25:28 am »
FPC already does some of this stuff in a way that I guess you could call it a auto initialize

Var
   MyVariable :ABasicaType = 0;

begin
 your code..

This of course will zero the variable each time the function is entered .


Then you have the Advanced records which I think was already mentioned here which comes with initialize and finalize constructor options but may only be supported in 3.3 or could be 3.2
 
 But in any case this should allow for managed code to do what ever is needed upon entry to the function.

am I off track here  ?
The only true wisdom is knowing you know nothing

Warfley

  • Hero Member
  • *****
  • Posts: 1499
Re: Nullable and Immutable types
« Reply #7 on: January 03, 2021, 01:35:27 am »
I created my own Optional type some time ago and used management operators to initialize it (Mode Delphi):

Code: Pascal  [Select][+][-]
  1. type
  2.   TEmptyOptional = record;
  3.  
  4.   { TOptional }
  5.  
  6.   TOptional<T> = record
  7.   public type
  8.     PT = ^T;
  9.   private
  10.     FHasValue: Boolean;
  11.     FValue: T;
  12.  
  13.     class operator Initialize(var a: TOptional<T>);
  14.   public
  15.     constructor Create(constref AValue: T);
  16.  
  17.     function ValuePtr: PT; inline;
  18.     function Value: T; inline;
  19.     function GetOrDefault(constref def: T): T;
  20.  
  21.     class operator Implicit(constref AValue: T): TOptional<T>; inline;
  22.     class operator Explicit(constref AValue: T): TOptional<T>; inline;
  23.     class operator Implicit(constref AValue: TEmptyOptional): TOptional<T>; inline;
  24.     class operator Explicit(constref AValue: TEmptyOptional): TOptional<T>; inline;
  25.     class operator Implicit(constref opt: TOptional<T>): Boolean; inline;
  26.     class operator Explicit(constref opt: TOptional<T>): Boolean; inline;
  27.     class operator LogicalNot(constref opt: TOptional<T>): Boolean; inline;
  28.  
  29.     property HasValue: Boolean read FHasValue;
  30.  
  31.     class function Empty: TOptional<T>; static; inline;
  32.   end;
  33.  
  34. function EmptyOptional: TEmptyOptional; inline;
  35.  
  36. implementation
  37.  
  38. { TOptional }
  39.  
  40. class operator TOptional<T>.Initialize(var a: TOptional<T>);
  41. begin
  42.   a.FHasValue := False;
  43. end;
  44.  
  45. constructor TOptional<T>.Create(constref AValue: T);
  46. begin
  47.   FHasValue := True;
  48.   FValue := AValue;
  49. end;
  50.  
  51. function TOptional<T>.ValuePtr: PT;
  52. begin
  53.   If not HasValue then
  54.     raise ENoValuePresentException.Create('Trying to access value of an empty optional');
  55.   Result := @FValue;
  56. end;
  57.  
  58. function TOptional<T>.Value: T;
  59. begin
  60.   If not HasValue then
  61.     raise ENoValuePresentException.Create('Trying to access value of an empty optional');
  62.   Result := FValue;
  63. end;
  64.  
  65. function TOptional<T>.GetOrDefault(constref def: T): T;
  66. begin
  67.   If HasValue then
  68.     Result := FValue
  69.   else
  70.     Result := def;
  71. end;
  72.  
  73. class operator TOptional<T>.Implicit(constref AValue: T): TOptional<T>;
  74. begin
  75.   Result.FHasValue := True;
  76.   Result.FValue := AValue;
  77. end;
  78.  
  79. class operator TOptional<T>.Explicit(constref AValue: T): TOptional<T>;
  80. begin
  81.   Result.FHasValue := True;
  82.   Result.FValue := AValue;
  83. end;
  84.  
  85. class operator TOptional<T>.Implicit(constref AValue: TEmptyOptional): TOptional
  86.   <T>;
  87. begin
  88.   Result.FHasValue := False;
  89. end;
  90.  
  91. class operator TOptional<T>.Explicit(constref AValue: TEmptyOptional): TOptional
  92.   <T>;
  93. begin
  94.   Result.FHasValue := False;
  95. end;
  96.  
  97. class operator TOptional<T>.Implicit(constref opt: TOptional<T>): Boolean;
  98. begin
  99.   Result := opt.HasValue;
  100. end;
  101.  
  102. class operator TOptional<T>.Explicit(constref opt: TOptional<T>): Boolean;
  103. begin
  104.   Result := opt.HasValue;
  105. end;
  106.  
  107. class operator TOptional<T>.LogicalNot(constref opt: TOptional<T>): Boolean;
  108. begin
  109.   Result := not opt.HasValue;
  110. end;
  111.  
  112. class function TOptional<T>.Empty: TOptional<T>;
  113. begin
  114.   Result.FHasValue := False;
  115. end;
  116.  
  117. function EmptyOptional: TEmptyOptional;
  118. begin
  119.   // Nothing to do here
  120. end;
  121.  

The main difference to the TNullable example (except for the management initialization) is that it does not take pointers to be nullable, as this requires a runtime check, but can be cleared by using a custom dummy type TEmptyOptional, which is generated via the function emptyOptional, i.e.:
Code: Pascal  [Select][+][-]
  1. myOpt := EmptyOptional;
It also has some more casts that make it's usage easier (like implicit cast to bool to check for it's existance)

If you want to make that type single assignment readonly you can do the following:
1. remove the ValuePtr function, as this allows writing to the value without our access.
2. Implement the copy class operator as follows:
Code: Pascal  [Select][+][-]
  1. class operator TOptional<T>.Copy(constref aSrc: TOptional<T>;
  2.                                       var aDst: TOptional<T>);
  3. begin
  4.   if aDst then
  5.     raise EAlreadyAssignedQuestion.Create('Trying to override already assigned optional');
  6.   aDst.FHasValue := aSrc.FHasValue;
  7.   if aSrc then
  8.     aDst.FValue := aSrc.FValue;
  9. end;

Note: you also need to define EAlreadyAssignedQuestion as exception type:
Code: Pascal  [Select][+][-]
  1. EAlreadyAssignedQuestion = class(Exception);

But this is only a runtime check and is not enforced on compiletime
« Last Edit: January 03, 2021, 01:37:45 am by Warfley »

Peter H

  • Sr. Member
  • ****
  • Posts: 272
Re: Nullable and Immutable types
« Reply #8 on: January 03, 2021, 01:49:28 am »
@Jamie
I tried this, gives a compile error:
Code: Pascal  [Select][+][-]
  1. Type testtype = record
  2.    a:integer;
  3.    end;
  4.  
  5. procedure TForm1.btnDisconnectClick(Sender: TObject);
  6. var
  7.   a:testtype = 0;
  8. .....
  9.                  

Is a modeswitch required?
(I use {$mode objfpc}{$H+} FPC 3.3.1)
« Last Edit: January 03, 2021, 01:59:57 am by Peter H »

Warfley

  • Hero Member
  • *****
  • Posts: 1499
Re: Nullable and Immutable types
« Reply #9 on: January 03, 2021, 02:03:29 am »
@Jamie
I tried this, gives a compile error:
I think the syntax is this:
Code: Pascal  [Select][+][-]
  1. type
  2.   TTestRec = record
  3.     A, B: Integer;
  4.   end;
  5.  
  6. var
  7.   test: TTestRec = (A: 42; B: 32);

Peter H

  • Sr. Member
  • ****
  • Posts: 272
Re: Nullable and Immutable types
« Reply #10 on: January 03, 2021, 02:11:48 am »
The question was how to zero out a variable or record. Initializing is possible, but maybe painful for large records, especially if the record is generated by a template.

Here is a brute force solution that works on any FPC version:
Code: Pascal  [Select][+][-]
  1. Type testtype = record
  2.    a:integer;
  3.    end;
  4.  
  5. procedure TForm1.btnDisconnectClick(Sender: TObject);
  6. var
  7.   a:testtype;
  8. begin
  9.   FillChar(a,sizeof(a),0);
  10. ......
  11.  
:D
« Last Edit: January 03, 2021, 02:15:23 am by Peter H »

Warfley

  • Hero Member
  • *****
  • Posts: 1499
Re: Nullable and Immutable types
« Reply #11 on: January 03, 2021, 02:22:31 am »
If you write the record yourself and you have FPC 3.2 or above, I would recommend just implementing the initialization operator, so when using this record you don't have to think about it, this can also be done using fillchar:
Code: Pascal  [Select][+][-]
  1. class operator TMyType.Initialize(var a: TMyType);
  2. begin
  3.   FillChar(self, sizeof(self), #00);
  4. end;

It should be added that if the record contains managed types that don’t default to 0, fillchar will break the data integrity
« Last Edit: January 03, 2021, 03:26:35 am by Warfley »

jamie

  • Hero Member
  • *****
  • Posts: 6130
Re: Nullable and Immutable types
« Reply #12 on: January 03, 2021, 03:53:46 am »
People keep forgetting about the Object model..

that can do just about anything the advanced record can do..

Infact I would bet the compiler just uses bits and pieces of it

just change the Record to a OBJECT..

put in a simple INIT procedure method...



and when in use just call that at the start of the operation and when the method is called you can code there all that you need for the default stuff.

also Objects do not need to be created dynamic, they can live on the stack or heap and they behave pretty much the same way as records do.

EDIT:
 Apparently the RECORD also supports standard methods too. oh well
so what's the real difference here ? Maybe objects don't have the operators I guess.

« Last Edit: January 03, 2021, 04:02:46 am by jamie »
The only true wisdom is knowing you know nothing

Thaddy

  • Hero Member
  • *****
  • Posts: 14373
  • Sensorship about opinions does not belong here.
Re: Nullable and Immutable types
« Reply #13 on: January 03, 2021, 05:52:08 am »
If you write the record yourself and you have FPC 3.2 or above, I would recommend just implementing the initialization operator, so when using this record you don't have to think about it, this can also be done using fillchar:
Code: Pascal  [Select][+][-]
  1. class operator TMyType.Initialize(var a: TMyType);
  2. begin
  3.   FillChar(self, sizeof(self), #00);
  4. end;

It should be added that if the record contains managed types that don’t default to 0, fillchar will break the data integrity
Well, I would do:
Code: Pascal  [Select][+][-]
  1. class operator TMyType.Initialize(var a: TMyType);
  2. begin
  3.   a := Default(TMyType);
  4. end;
For the reason you mention and that's where the default() intrinsic is for.
« Last Edit: January 03, 2021, 05:59:10 am by Thaddy »
Object Pascal programmers should get rid of their "component fetish" especially with the non-visuals.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5478
  • Compiler Developer
Re: Nullable and Immutable types
« Reply #14 on: January 03, 2021, 12:47:01 pm »
Just for information: FPC has an TNullable<> in unit Nullable since August as well. It will also be part of 3.2.2.

 

TinyPortal © 2005-2018