Recent

Author Topic: Immutable data types  (Read 9526 times)

Bogen85

  • Hero Member
  • *****
  • Posts: 595
Immutable data types
« on: September 29, 2022, 04:31:31 am »
Yes, I know, I've seen this discussed a few times...

It seems like some of the issues (primarily related to how it would fit with pascal syntax) are:
  • What would it look like? Would it be a something other than var?
  • Would it be an attribute to var?
  • How would initial assignment be done?

Doing complex initial assignment in the var section (especially if it uses parameters from parent function or needs to make function calls is tedious...).

If with additional keywords it something like the following could work within existing pascal syntax (suggested names are just example names, not necessarily what I'm suggesting):

Code: Pascal  [Select][+][-]
  1. program immutable;
  2.  
  3.   procedure something (const a, b, c: integer);
  4.     var
  5.       d: integer; immutable;
  6.       e: integer; immutable;
  7.       f: integer; immutable;
  8.     begin
  9.       d := a + 4; final;
  10.       e := b + 5; final;
  11.       f := c + 6; final;
  12.       writeln ('a: ', a);
  13.       writeln ('b: ', b);
  14.       writeln ('c: ', c);
  15.       writeln ('d: ', d);
  16.       writeln ('e: ', e);
  17.       writeln ('f: ', f);
  18.     end;
  19.  
  20. begin
  21.   something (1, 2, 3);
  22. end.
  23.  

Using the immutable keyword, the final keyword would not likely not be used.
Basically with immutable the first assignment would lock in the value, and the compiler would not allow for further assignment.

If there was enough community and developer buy in to to such a feature change, I might be willing to do a lot of the legwork, providing I'd get sufficient assistance.




marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: Immutable data types
« Reply #1 on: September 29, 2022, 09:53:52 am »
I don't see a description of what final would do, but modifiers afaik don't apply to statement lines. The closest I can come up with as analogous syntax would be aligned() so the syntax probably would be more

Code: Pascal  [Select][+][-]
  1.   f := final(c + 6);
  2.  



Warfley

  • Hero Member
  • *****
  • Posts: 1499
Re: Immutable data types
« Reply #2 on: September 29, 2022, 11:24:57 am »
Immutability must be transitive otherwise it is useless. If i have an immutable integer, but can make a mutable pointer to it, it is effectively not immutable.

So considering your example
Code: Pascal  [Select][+][-]
  1. var
  2.   i: Integer; immutable;
  3.   pi: PInteger; immutable;
  4. begin
  5.   i := 42; // Initial assignment is fine, any change afterwards would be violation
  6.   pi := @i; // Also fine because initial assignemnt
  7.   pi^ := 32; // This does not change pi but the pointer behind. As only pi is immutable not what it points towards this is fine, but violates the immutability of i
  8. end;
And this is generally not decidable:
Code: Pascal  [Select][+][-]
  1. var
  2.   i: Integer; immutable;
  3.   j: Integer;
  4.   pi: PInteger; immutable;
  5. begin
  6.   i := 42; // Initial assignment is fine, any change afterwards would be violation
  7.   pi := ifThen(Random(2) = 1, @i, @j); // Initial assignment is fine
  8.   pi^ := 32; // In 50% of cases (when random is 1) pi will point to i, which would be a violation of it's immutability, but in the other 50% of cases this would point to j, which is mutable and therefore fine

So the immutability information must transitively be passed with the pointer information, so there must be the concept of a pointer to an immutable object. But that pointer could also be mutable and immutable. Also there can be a pointer to that pointer and so on.
Without this in a language like pascal, which heavily relies on pointers a concept of immutability would be pointless.

So what you end up with is having to incorporate this into your type system, so for example:
Code: Pascal  [Select][+][-]
  1. type
  2.   ImmutableInt = immutable Integer;
  3.   PImmutableInt = ImmutableInt^;
  4.  
  5. var
  6.   i: ImmutableInt;
  7.   pi: PImmutableInt;
  8. begin
  9.   i := 42;
  10.   pi := @i;
  11.   pi^ := 32; // Error because pi dereferences to an immutable object
  12.  

And basically what we have here is the exact way the C typesystem works.

Zaher

  • Hero Member
  • *****
  • Posts: 679
    • parmaja.org
Re: Immutable data types
« Reply #3 on: September 29, 2022, 12:44:26 pm »
How the compiler will know it the value locked , you need to add AI  8)

Code: [Select]
program immutable;


  procedure something(var d: integer);
    begin
      d := d + 1; //compiler will raise error here in second call
    end;

var
d: integer; immutable;
begin
  d := 1;
  something (d);

  d := 2; final;
  something (d);
end.
[code]

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: Immutable data types
« Reply #4 on: September 29, 2022, 01:34:02 pm »
Immutability must be transitive otherwise it is useless. If i have an immutable integer, but can make a mutable pointer to it, it is effectively not immutable.

The easiest way is to declare a value and allow constrained modification, followed by a custom block during which it's immutable. On exit from the block it's no longer in scope:

Code: Pascal  [Select][+][-]
  1. for i: integer= 0 to 9 do begin
  2. ...
  3. end;
  4.  

...and we all know what the developers think about /that/ sort of thing.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Warfley

  • Hero Member
  • *****
  • Posts: 1499
Re: Immutable data types
« Reply #5 on: September 29, 2022, 01:46:35 pm »
Also such a simple immutability concept must extend to methods:
Code: Pascal  [Select][+][-]
  1. {$ModeSwitch AdvancedRecords}
  2. type
  3.   TTestRec = record
  4.     i: Integer;
  5.     procedure Increment;
  6.   end;
  7.  
  8. procedure TTestRec.Increment;
  9. begin
  10.   Inc(Self.i);
  11. end;
  12.  
  13. var
  14.   r: TTestRec = (i: 0); immutable;
  15. begin
  16.   Inc(r.i); // Should throw an error because r is immutable
  17.   r.Increment; // What about this?
  18. end;

So you need a notion which methods can alter (i.e. for which methods self is immutable). E.g.:
Code: Pascal  [Select][+][-]
  1.   TTestRec = record
  2.     i: Integer;
  3.     procedure Increment; immutable;
  4.   end;
And thereby re-invent the C++ const system.

Bogen85

  • Hero Member
  • *****
  • Posts: 595
Re: Immutable data types
« Reply #6 on: September 29, 2022, 01:48:51 pm »
How the compiler will know it the value locked , you need to add AI  8)

Rhetorical answer, I know: So, C/C++/Rust all have AI's built into them? (And C/C++ has that AI for more than 20 years?)

But to get back to Pascal. And yes, a lot more involved then this, but at a basic level the compiler just has to keep track when emitting code that when it sees the the first assignment, it marks that identifier internally as already assigned. Any attempt to emit code that would result in another assignment, would result in an error.

FPC can already warn you (and you can make that warning an error) that you are trying to access a variable that has not been initialized yet. So at some level it is already do that kind of tracking.

Zaher

  • Hero Member
  • *****
  • Posts: 679
    • parmaja.org
Re: Immutable data types
« Reply #7 on: September 29, 2022, 01:56:37 pm »
It is exists also D lang , and they have good examples https://dlang.org/spec/const3.html

If you need add this feature you need to modify other syntax of language too not just adding new modifier (or AI  :D ).
« Last Edit: September 29, 2022, 02:04:51 pm by Zaher »

Bogen85

  • Hero Member
  • *****
  • Posts: 595
Re: Immutable data types
« Reply #8 on: September 29, 2022, 01:59:07 pm »
The easiest way is to declare a value and allow constrained modification, followed by a custom block during which it's immutable. On exit from the block it's no longer in scope:

Code: Pascal  [Select][+][-]
  1. for i: integer= 0 to 9 do begin
  2. ...
  3. end;
  4.  

...and we all know what the developers think about /that/ sort of thing.

MarkMLl

And currently that is not possible. Something similar can already be achieved where the index is read only and the index can't be modified.
The following works (if you build and install FPC from current git sources), but there is a lot of overhead involved to support it.

Code: Pascal  [Select][+][-]
  1. {$mode delphi}
  2. {$modeswitch anonymousfunctions}
  3. {$modeswitch functionreferences}
  4.  
  5. program readonlyloop;
  6.  
  7. type
  8.   tLoop = reference to procedure (const i, limit: integer);
  9.  
  10.   procedure main;
  11.     var
  12.       L1: tLoop;
  13.  
  14.     begin
  15.       L1 := procedure (const i, limit: integer) begin
  16.         if i >= limit then exit;
  17.         writeln ('at local iteration ', i);
  18.         L1 (i+1, limit);
  19.       end;
  20.       L1 (10, 25);
  21.     end;
  22.  
  23. begin
  24.   main;
  25. end.
  26.  

So, FPC can already do this sort of immutablity, albeit the syntax looks odd, and there would need to be a lot of optimization added to make that work efficiently.

Bogen85

  • Hero Member
  • *****
  • Posts: 595
Re: Immutable data types
« Reply #9 on: September 29, 2022, 02:00:57 pm »
It is exists also D lang , and they have good examples https://dlang.org/spec/const3.html

Yes, I'm familiar with D lang, my language list in my rhetorical answer was not exhaustive...  :D

Thaddy

  • Hero Member
  • *****
  • Posts: 14200
  • Probably until I exterminate Putin.
Re: Immutable data types
« Reply #10 on: September 29, 2022, 02:01:05 pm »
No AI involved.
Just a Pascal range, like
Code: Pascal  [Select][+][-]
  1. program test;
  2. type Tmyrange = 0..9;
  3. var
  4.   i: Tmyrange;
  5. begin
  6.   for i in Tmyrange do writeln(i);
  7. end.
Here I is not an index, but content. The index itself is a good example of immutable. You can't even see it... :D
Specialize a type, not a var.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: Immutable data types
« Reply #11 on: September 29, 2022, 02:09:33 pm »
Changing the type system might be a too big job for an initial project/feature in the compiler.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
Re: Immutable data types
« Reply #12 on: September 29, 2022, 02:10:39 pm »
Something similar can already be achieved where the index is read only and the index can't be modified.
The following works (if you build and install FPC from current git sources), but there is a lot of overhead involved to support it.

Code: Pascal  [Select][+][-]
  1. {$mode delphi}
  2. {$modeswitch anonymousfunctions}
  3. {$modeswitch functionreferences}
  4.  
  5. program readonlyloop;
  6.  
  7. type
  8.   tLoop = reference to procedure (const i, limit: integer);
  9.  
  10.   procedure main;
  11.     var
  12.       L1: tLoop;
  13.  
  14.     begin
  15.       L1 := procedure (const i, limit: integer) begin
  16.         if i >= limit then exit;
  17.         writeln ('at local iteration ', i);
  18.         L1 (i+1, limit);
  19.       end;
  20.       L1 (10, 25);
  21.     end;
  22.  
  23. begin
  24.   main;
  25. end.
  26.  

So, FPC can already do this sort of immutablity, albeit the syntax looks odd, and there would need to be a lot of optimization added to make that work efficiently.

You can just as well use a nested function pointer together with an anonymous function. Much less overhead this way. ;)

Code: Pascal  [Select][+][-]
  1. {$mode delphi}
  2. {$modeswitch anonymousfunctions}
  3. {$modeswitch nestedprocvars}
  4.  
  5. program readonlyloop;
  6.  
  7. type
  8.   tLoop = procedure (const i, limit: integer) is nested;
  9.  
  10.   procedure main;
  11.     var
  12.       L1: tLoop;
  13.  
  14.     begin
  15.       L1 := procedure (const i, limit: integer) begin
  16.         if i >= limit then exit;
  17.         writeln ('at local iteration ', i);
  18.         L1 (i+1, limit);
  19.       end;
  20.       L1 (10, 25);
  21.     end;
  22.  
  23. begin
  24.   main;
  25. end.

Regarding some immutable mechanism: for the JVM target FPC already supports immutability in the form of a separate section inside class and record declarations, but only for external classes:

Code: Pascal  [Select][+][-]
  1.   ANNfcEvent = class sealed external 'android.nfc' name 'NfcEvent' (JLObject)
  2.   public
  3.     final var
  4.       fnfcAdapter: ANNfcAdapter; external name 'nfcAdapter';
  5.   end;
  6.  

This is not supported on other platforms, because this would require full DFA support and thus this currently simply can not be supported.

Bogen85

  • Hero Member
  • *****
  • Posts: 595
Re: Immutable data types
« Reply #13 on: September 29, 2022, 02:15:27 pm »
No AI involved.
Just a Pascal range, like
Code: Pascal  [Select][+][-]
  1. program test;
  2. type Tmyrange = 0..9;
  3. var
  4.   i: Tmyrange;
  5. begin
  6.   for i in Tmyrange do writeln(i);
  7. end.
Here I is not an index, but content. The index itself is a good example of immutable. You can't even see it... :D

Yes, and it can't be modified inside that loop, agreed.
Code: Pascal  [Select][+][-]
  1. program test;
  2.  
  3. type
  4.   Tmyrange = 0..9;
  5. var
  6.   i: Tmyrange;
  7. begin
  8.   for i in Tmyrange do writeln (i);
  9.  
  10.   for i in Tmyrange do begin
  11.     writeln (i);
  12.     i := succ(i);
  13.   end;
  14. end.
  15.  

Code: Text  [Select][+][-]
  1. Free Pascal Compiler version 3.3.1 [2022/09/26] for x86_64
  2. Copyright (c) 1993-2022 by Florian Klaempfl and others
  3. Target OS: Linux for x86-64
  4. Compiling ./lazforum/test_loop.pas
  5. test_loop.pas(12,7) Error: Illegal assignment to for-loop variable "i"
  6. test_loop.pas(16) Fatal: There were 1 errors compiling module, stopping
  7. Fatal: Compilation aborted
  8. Error: /home/shared-development/fpc_usr/lib/fpc/3.3.1/ppcx64 returned an error exitcode
  9.  


Also, i is exposed.
Code: Pascal  [Select][+][-]
  1. program test;
  2.  
  3. type
  4.   Tmyrange = 0..9;
  5. var
  6.   i: Tmyrange;
  7. begin
  8.   writeln (i);
  9.   for i in Tmyrange do writeln (i);
  10.   writeln (i);
  11. end.
  12.  

And it's final value accessible after the loop, and still actually modifiable.

Code: Pascal  [Select][+][-]
  1. program test;
  2.  
  3. type
  4.   Tmyrange = 0..9;
  5. var
  6.   i: Tmyrange;
  7.  
  8.   procedure something;
  9.   begin
  10.     inc(i);
  11.     writeln ('something ', i);
  12.   end;
  13.  
  14. begin
  15.   writeln ('before ', i);
  16.   for i in Tmyrange do begin
  17.     writeln ('inside ', i);
  18.     something;
  19.   end;
  20.   writeln ('after ', i);
  21. end.
  22.  

Code: Text  [Select][+][-]
  1. before 0
  2. inside 0
  3. something 1
  4. inside 2
  5. something 3
  6. inside 4
  7. something 5
  8. inside 6
  9. something 7
  10. inside 8
  11. something 9
  12. after 9
  13.  

« Last Edit: September 29, 2022, 02:17:12 pm by Bogen85 »

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
Re: Immutable data types
« Reply #14 on: September 29, 2022, 02:19:01 pm »
And it's final value accessible after the loop, and still actually modifiable.

But before and after the loop the value of the index variable is considered undefined (except for the later if the loop has been left with a Break or goto). This is more obvious if you use a function instead of the main body, because then it won't necessarily be 0 before the loop.

 

TinyPortal © 2005-2018