Recent

Author Topic: Immutable data types  (Read 9414 times)

SymbolicFrank

  • Hero Member
  • *****
  • Posts: 1313
Re: Immutable data types
« Reply #75 on: October 05, 2022, 10:13:09 am »
I think the main distinction is, that while you can emulate the functionality with a read-only property, that isn't the only use-case for them. Like, you can make a read-only 'Count' property, that returns the amount of values in a list. It's up to the programmer, the compiler doesn't enforce it.

And the idea about using anonymous functions is to emulate how languages like Haskell do it: you store the mutations required to get from the old value(s) to the new one. Then again, you can also use a regular function to do that, of course.

Bogen85

  • Hero Member
  • *****
  • Posts: 595
Re: Immutable data types
« Reply #76 on: October 05, 2022, 03:04:03 pm »
I think the main distinction is, that while you can emulate the functionality with a read-only property, that isn't the only use-case for them. Like, you can make a read-only 'Count' property, that returns the amount of values in a list. It's up to the programmer, the compiler doesn't enforce it.

And the idea about using anonymous functions is to emulate how languages like Haskell do it: you store the mutations required to get from the old value(s) to the new one. Then again, you can also use a regular function to do that, of course.

Agreed. Which is what I stated earlier.

The reason why I say that anonymous functions solves this problem, is because my original source code musings from this initial post can use the following (now supported in FPC) to achive immutable variable assignments that the compiler enforces (but yes, as others have stated, could be bypassed with pointers.)

And it does not always need to be anonymous functions. It can be named nested functions. But the point is that const var parameters satisfy cursory compiled enforced immutability and by leveraging them one can cut down the required number of var declarations overall.

And obviously with top level unit functions. All depends on scoping needs.

Where anonymous functions are useful in this mix is for custom iterator and other types of callbacks where what is passed into the anonymous functions "callback" is received as const var parameters. (As I discussed earlier).

Bogen85

  • Hero Member
  • *****
  • Posts: 595
Re: Immutable data types
« Reply #77 on: October 05, 2022, 07:36:21 pm »
And of course I'm fully aware that the const function parameter compile time checking is shallow, and not deep.

Arioch

  • Sr. Member
  • ****
  • Posts: 421
Re: Immutable data types
« Reply #78 on: October 05, 2022, 11:28:57 pm »
Generally, if you have a read-only property, you set it once, in the constructor. The constructor has a formula to calculate it from other values. Once.

Sounds like the same thing to me.

...do you by chance create ad hoc object with a modifiable property every time you need a variable?

Sounds like the same thing to me.

Warfley

  • Hero Member
  • *****
  • Posts: 1499
Re: Immutable data types
« Reply #79 on: October 06, 2022, 04:39:23 pm »
Yes, I know. From functional languages, but different.

Like querying a read-only database: you can only create new values by mutating old ones. Like, a view with one or more calculated fields that reference other fields. Or, like Lisp.
The concept of immutable datatypes as in functional languages, is a bit different than what usually is thought of with immutability in imperative languages. Functional languages like Haskell are stateless (at least the pure ones), where the whole program just consists of expressions. As you don't have single instructions there is no such thing as state that can be changed, and all you can do is take values as input and put them into functions that produce an output.
This is also a common paradigm when working in imperative languages when working with atomic types. Take this example:
Code: Pascal  [Select][+][-]
  1. x := 3 + 4 * 2;
You could rewrite this as:
Code: Pascal  [Select][+][-]
  1. x.SetValue(4);
  2. x.Mul(2);
  3. x.Add(3);
While with type helpers this would be possible, nobody does this, so atomic types in Pascal are mostly immutable, in the sense that you usually don't alter the state of an object but create a new object from an expression. Note that the following is also fllowing this paradigm:
Code: Pascal  [Select][+][-]
  1. x := 1;
  2. for i:=0 to 10 do
  3.   x := x * i;
Even though x is changed, the objects itself are still immutable, because every iteration a new object is created and "just given the same name".

This might seem overcomplicated, or as MarkMLI put it "computersciency crap" when considering atomic types, but this is actually very useful for writing readable code. For example when instead of using integers, we consider the gmp unit. The computation above (3 + 4 * 2) completely using GMP types looks like this:
Code: Pascal  [Select][+][-]
  1. var
  2.   x: mpz_t;
  3. begin
  4.   mpz_init_set_ui(x, 4);
  5.   mpz_mul_ui(x, x, 2);
  6.   mpz_add_ui(x, x, 3);
But the GMP unit also provides wrapper types that are designed to be treated as immutables, by creating temporary objects:
Code: Pascal  [Select][+][-]
  1. var
  2.   x: MPInteger;
  3. begin
  4.   x := MPInteger(4) * 2 + 3;
This is much more intuitive to read than the former, and is completely immutable, MPInteger(4) creates a new object, *2 than takes this object and multiplies it by 2 and writes the result in a new object, which is then added with 3 to the final object that is then written into x. During the whole process no Object was modified after it's creation, and it's arguably better readable code.

Also a lot of the classical pascal functions are not following this paradigm:
Take the following:
Code: Pascal  [Select][+][-]
  1. Inc(x, 3);
  2. // vs
  3. x := x + 3;
  4. // Or
  5. Delete(str, 0, 3);
  6. // vs
  7. str := str.Substring(3);
I personally find this paradigm to produce much more readable code, because the state change is made explicit. When writing str := ... I know just from looking at that, that afterwards str will be something different, while with Delete I have to know that function to know that it changes str. I think that generally var and out parameters should be avoided as much as possible to make any changes explicit and directly spottable.
It also means that there is only one way to change things, if there is a := the variable changes, if not, than you can assume it will still be the same


But these are immutable datatypes, but what the discussion here was about are immutable variabels, to cover also pointer to such variables, immutable references.
Immutable references are different in the sense that you can basically ensure that if you "lend" someone an object, that it will come back unchanged. For example, assume you have a config class, which is used by many other classes to read out things like directories, user config, etc. Simultaniously you might not want to create a copy of said configuration for all cases (e.g. when the user should be able to change said config it would not be wise to have to propagete that change throughout all the classes again).
Therefore if you have a method of making immutable references, you can signal to the code getting this reference that it can be read, but that it is probably not a unique copy and therefore changing it might have other consequences outside the current bit of code. It's a form of documentation, the violation of which is enforced by the compiler.

Of course this can be used with immutable datatypes, but the core difference here is, that you can have an immutable references to mutable object. In the config example above, there might be a class which can actually change the config, e.g. some config editor form or something similar, so the class must be mutable. So we have multiple references to the same object, some mutable, some immutable, while immutable datatypes will always produce immutable.

So I think it is important to distinquish here. Immutable datatypes have their advantages, but they are generally a design paradigm which you have to alter your code around. Immutable references on the other hand are just a security mechanism to enforce assumptions made on the code, but generally the code would look identical if you removed the immutability (e.g. if you have a const variable in c and you remove the const everywhere, the code will work exactly the same, you just have less compiler checking if your ownership assumptions hold true)
« Last Edit: October 06, 2022, 04:46:28 pm by Warfley »

MarkMLl

  • Hero Member
  • *****
  • Posts: 6646
Re: Immutable data types
« Reply #80 on: October 06, 2022, 05:05:11 pm »
This might seem overcomplicated, or as MarkMLI put it "computersciency crap"

At last! The recognition I have always craved!!! :-)

Quote
So I think it is important to distinquish here. Immutable datatypes have their advantages, but they are generally a design paradigm which you have to alter your code around. Immutable references on the other hand are just a security mechanism to enforce assumptions made on the code, but generally the code would look identical if you removed the immutability (e.g. if you have a const variable in c and you remove the const everywhere, the code will work exactly the same, you just have less compiler checking if your ownership assumptions hold true)

The bottom line, however, is that Pascal does purport to still be a systems programming language, and as such to provide datatypes and operations with a relatively straightforward mapping onto the underlying architecture. And while I am obviously aware of various machines with dataflow architectures (the best known and arguably most successful being the HAL Series) and am enthusiastic about the potential of atomic message-passing at the microkernel or hardware level I think the emphasis should be on languages such as Pascal /enabling/ or /supporting/ this style of programming rather than advertising it as a significant and immediately-accessible extension.

And I have already made the point about one area that cries out for immutable references being public storage of (objects representing) Lazarus/LCL forms.

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

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11351
  • FPC developer.
Re: Immutable data types
« Reply #81 on: October 06, 2022, 05:24:00 pm »
I think inc() is more an intrinsic that stuck in the language than a real feature.

It would like judging C badly for their ++ and -- operators (that were basically PDP intrinsics).

Intrinsics sometimes get legalized into the language; it happens, but it is never elegant.
« Last Edit: October 06, 2022, 05:28:21 pm by marcov »

MarkMLl

  • Hero Member
  • *****
  • Posts: 6646
Re: Immutable data types
« Reply #82 on: October 06, 2022, 05:38:50 pm »
It would like judging C badly for their ++ and -- operators (that were basically PDP intrinsics).

Let's face it, very few people defend ++ and -- and arguably they- like most if not all direct pointer manipulation- should really be reserved for competent programmers.

One thing I would add though is that apparently ++ and -- in C predate the PDP series. I can't provide an immediate reference for this, but my recollection is that the first version of UNIX was written in quasi-assembler which included comparable operations despite the target system not implementing them directly, and the result was that when C was presented as a high-level replacement it really had to include the same facilities.

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

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11351
  • FPC developer.
Re: Immutable data types
« Reply #83 on: October 06, 2022, 06:03:45 pm »
One thing I would add though is that apparently ++ and -- in C predate the PDP series.

The B language wikipedia page seems to say something like that. One could argue that K&R might have had advance knowledge, etc etc, but lets not go there.

Let's just turn it around, where is the rationale for ++/-- then?

MarkMLl

  • Hero Member
  • *****
  • Posts: 6646
Re: Immutable data types
« Reply #84 on: October 06, 2022, 06:27:42 pm »
The B language wikipedia page seems to say something like that. One could argue that K&R might have had advance knowledge, etc etc, but lets not go there.

The Wp page on Unix explicitly says that early versions of unix were coded in assembler, but I think I've seen more detail than that somewhere. I'd speculate- without proof- that Thompson had atomic "decrement-compare" and "compare-increment" macros to implement P/V semaphores, and that these had been repurposed for extensive other use.

Quote
Let's just turn it around, where is the rationale for ++/-- then?

The canonical C example codes make much of concise pointer operations with ++ or (less often) --, assumption that nil equates to zero hence false, and so on. But Sven's gone to some trouble to educate me as to how, as the language has been gradually tightened up, those operators have been recognised as problematic.

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

Bogen85

  • Hero Member
  • *****
  • Posts: 595
Re: Immutable data types
« Reply #85 on: October 07, 2022, 04:35:15 am »
Quote
Let's just turn it around, where is the rationale for ++/-- then?

The canonical C example codes make much of concise pointer operations with ++ or (less often) --, assumption that nil equates to zero hence false, and so on. But Sven's gone to some trouble to educate me as to how, as the language has been gradually tightened up, those operators have been recognised as problematic.

MarkMLl

Yeah... so people can write:
Code: C  [Select][+][-]
  1. while(*a++ = *b++); // and that is obvious to others what that means???
Back before optimizing compilers.... maybe it was needed to produce optimal code...

Certainly not needed with any decent modern C compiler... (in the past 2-3 decades, maybe longer)

440bx

  • Hero Member
  • *****
  • Posts: 3921
Re: Immutable data types
« Reply #86 on: October 07, 2022, 05:13:40 am »
Yeah... so people can write:
Code: C  [Select][+][-]
  1. while(*a++ = *b++); // and that is obvious to others what that means???
Back before optimizing compilers.... maybe it was needed to produce optimal code...

Certainly not needed with any decent modern C compiler... (in the past 2-3 decades, maybe longer)
only *b equal zero will make that loop end, if it isn't zero at the start of the while it will go on until *b overflows (which for a qword, is for practical purposes, close to an infinite loop.)

On a different note, there are plenty of modern C compilers out there but, I've never seen one that comes remotely close to being decent.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Bogen85

  • Hero Member
  • *****
  • Posts: 595
Re: Immutable data types
« Reply #87 on: October 07, 2022, 05:50:46 am »
Yeah... so people can write:
Code: C  [Select][+][-]
  1. while(*a++ = *b++); // and that is obvious to others what that means???
Back before optimizing compilers.... maybe it was needed to produce optimal code...

Certainly not needed with any decent modern C compiler... (in the past 2-3 decades, maybe longer)
only *b equal zero will make that loop end, if it isn't zero at the start of the while it will go on until *b overflows (which for a qword, is for practical purposes, close to an infinite loop.)


But it is better to use the builtin, optimized, and tested strcpy, strncpy, and so forth.

Especially strncpy for the reasons you stated above...

But the above example is just as unsafe as strcpy for copying what is supposed to be a null-terminated string using char pointers...
And even strncpy is not safe... (if the source is not null-terminated...)

And for large copies, just keep your data in struct variables, and pass those around, as the compiler and builtin functions produce better block copy code than trying to roll your own...

Point being that unless doing embedded systems or drivers most of the lower level features of C are not really needed.

But discussing C to this detail is likely a bit offtopic for this forum... (and the subject...)  :) 8-)

« Last Edit: October 07, 2022, 05:55:10 am by Bogen85 »

alpine

  • Hero Member
  • *****
  • Posts: 1032
Re: Immutable data types
« Reply #88 on: October 07, 2022, 09:16:09 am »
One thing I would add though is that apparently ++ and -- in C predate the PDP series.

The B language wikipedia page seems to say something like that. One could argue that K&R might have had advance knowledge, etc etc, but lets not go there.

Let's just turn it around, where is the rationale for ++/-- then?
(My apologies for being off-topic)

AFAIK in the early days, when C was still in a development, it turned out that ++x compiled more tightly than x=x+1 and perhaps that was just enough to embrace it. At that time the C syntax wasn't so well established (shorthand assignments were =+, =- instead of +=, -=, typeless variables, etc.). Later, some C statements could be represented by a just a single instruction - e.g. on the PDP-11/VAX/M68K.

For example:
Code: C  [Select][+][-]
  1.   *--ptr; // maps to @-(Rn) addressing mode
  2.   *ptr++; // maps to @(Rn)+ addressing mode
  3.   *a++=*b++; // one instruction: move @(A1)+,@(A2)+
  4.   *--a=*--b; // one instruction: move @-(A1),@-(A2)
  5.   // etc.

Shorter writing is not to be neglected:
Code: C  [Select][+][-]
  1.   while( *a++ = *b++ ) ;
  2.     // IS
  3.   while( *b != NULL )
  4.   {
  5.     *a = *b;
  6.     a = a + 1;
  7.     b = b + 1;
  8.   }
Isn't any of these enough for rationale? Especially in the early seventies.

For somebody it may sound curious, but the first line can be more readable for a C developer than the expanded loop - he will recognize it instantly as he is used to it.
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

MarkMLl

  • Hero Member
  • *****
  • Posts: 6646
Re: Immutable data types
« Reply #89 on: October 07, 2022, 09:18:32 am »
But it is better to use the builtin, optimized, and tested strcpy, strncpy, and so forth.

Which had to be written in the first place. We're talking about an early language, contemporaneous with Pascal (which was by no means perfect), designed and implemented by people less steeped in the art than Wirth/Hoare and intended as a standalone replacement for assembler.

However my attitude has long been summed up by one of the Modula-2 compilers' taglines:

"I come to bury C, sir, not to praise him."

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

 

TinyPortal © 2005-2018