In FreePascal type helpers (something that does not even exist in Delphi) are alive and well.
But you can also change this to advanced records to make the same point.
I don't see how it is the same point. You just made an incapsulated object(record) with an exlicit mutating method.
Basically, you reiterated that FPC/Delphi does not have "immutable objects" and calling any method might change the internal state.
But we all know it and we do not expect it otherwise. You called a method - you are on its mercy now.
Here is no broken expectations, at least no more than usual.
from your point of view as a user you can assume it to be a black box.
This!
=====================
On helpers I'll have to see. My current understanding (shallow glance) is that FPC type helpers is the same as Delphi record helpers just renamed. Plus, FPC does not prohibit several different helpers be active at once. And so, i did not look any deeper.
Would those be compiler intrinsics, so that no one but compiler makers could create those helpers - it would've been okay. One compiler magic more, one less, no big deal. But they are not.
With people encouraged to make their own helpers - they have either go into self-censorship, identifying this feature as dangerous, or end up having different helpers in different libraries for the same type.
So they get the unpredictability of big (actually - unit-big) WITH clause. Some place up there far away, visibly unrelated, included some unit - and suddenly he identifiers you use in your code changed meaning. Hopefully thy would stop compiling, worse if they would compile yet change meaning.
Delphi's restriction "only one helper" pessimizes creating your own helpers for types RTL already mase helpers for. But not prohibit it.
Multiple helpers mode of FPC does not even have it.
Imagine i have two libraries, both interface database of cars, but differnent datasets: one has information for different plate numbers (as road police gathers, "instances" of cars), and other - for different models (as shops/commercials do, "classes" of cars),
While i only had one library, it was cool, fancy and fashionably pythonish.
UsedCar := 'VX-10574-RU'.GetCar;
CarModel := 'Volvo X5 Black'.GetCar;
Cuule, man, aintah?
But of course, i might want to integrate both datasets.
If my program user looks to buy a used car on esome -bay, then he would benefit from oth reading reviews of the car model, and reading "police story" about this specific instance, maybe it was into accidents.
So, i throw both units, accessing both datasets into my uses clause....
...and what does
string.GetCar even mean now?
And here we go back to your earlier statement:
it is easy to see a situation where one person is writing a type (or typehelper) and changes the definition of one method to now alter one of the fields, while the usage, where it is assumed to be constant, is made by a different person
Type helpers promote sudden and global change of the working code, without actually the sources of that code being touched.
Imagine i was lucky to have a lucky sequency in my uses.
uses .... CarHistoryDB, CarMagazineReviews, ....
....
CarModel := 'Volvo X5 Black'.GetCar;
Works like a charm.
Then the CarMagazineReviews library team decided they made bad name, ambiguos if not misleading. And they cheanged their helper to be publish
GetReviews instead.
Oooops, suddenly my old polished ocde i did not touch for 5 years changed the meaning and (hopefully) compiles no more. But if both heplers were returning IUnknown and being fancy trendy libraries provided OLEAuto runtime-binding interface... Ooooops - it only gives "catastrophic call failure" later in the runtime.
And then there was another string helpers, that also published a function
string.GetReviews - but those were reviews of parking lots for tourists.
Those calls suddenly got broken too!
Good luck with this mess...