One thing that's missing in FPC is object protocols, I mean like with statement in Python.most of the time they are not needed in pascal eg
The with statement already exists in FPC, but it's very simple, syntactic convenience.
# open returns a "context manager" object that implements methods __enter__ and __exit__, a protocol. with open("file.txt") as f: data = f.read() print(data)
1) with statement calls context manager's __enter__ in order to init some context, if optional "as f" is present, it is assigned to what __enter__ returns.
2) Execute statements in a block
3) call CM's __exit__ to close context. If block raised exception, this method receives exception in its arguments.
// C# has a "Using" statement, but it only calls a destructor of used object in the end. var TheCustomer: Customer; Using TheCustomer to obj do // "to obj" is optional begin // do something in a created context here obj.SomeMethod; // obj is returned by __enter__ // compiler calls obj.Destroy here end; // Given: Customer = class // implements "context manager" protocol for a Using statement procedure __enter__; function __enter__: Sometype; // returned value assigned "to obj" above procedure __exit__; procedure __rescue__(ex: Exception); end;
most of the time they are not needed in pascal egbut I agree it seems a bit more care free with out all that try/finally stuff ofcourse it shifts the responsibility for a proper destruction to the component writer instead it does not go away and I do not think that any component writer would like to take on more than it is absolutely necessary (my included). Look what happened with the build in for in support do you know many 3rd party controls that have build support?
function Open(const aFilename:TFilename):TFileStream; begin result := tfilestream.create(afilename,fmopenreadwriteorfmshareexclusive); end; procedure domytheng; begin with open("MyDataFile.Dat") do try read(Data, size); finally free end; end;
One thing that's missing in FPC is object protocols, I mean like with statement in Python.
The with statement already exists in FPC, but it's very simple, syntactic convenience.
# open returns a "context manager" object that implements methods __enter__ and __exit__, a protocol. with open("file.txt") as f: data = f.read() print(data)
What's wrong with?
f:=open("file.txt")
So, that construction somehow partly replaces RAII of C++, gives some "design by contract" abilities.
Also it can be used to program transactions with rollbacks.
Or using draw procedures in some graphic contexts, or action procedures in a game.
you have your init right there and when it fells off scope you have the destructor called automatically and it is as clean as your example
Keep in mind that I have not worked with object for a long long time so my facts might be upside down but the idea is there and I'm pretty sure can be made to work.
I do like the variable ability. In any case I'm all up for a new compiler but I'm warning you I'm not giving up my compatibility for any reason.
Although I broadly agree with you, there are some newer features in the language that have merits in extending the language by helping defensive programming (which I always try to do).
I don't see it either. The challenges of programming nowadays are not due to a lack of language syntax micro optimization. This is syntax navel-gazing, or syntax graffiti; people feel a need to mark a language as their own by adding something. And if you search long enough you'll find always some construct that can be a few chars shorter. But it makes the language as a whole more baroque and thus weaker.
On the subject of with statements, due to debugging related bugs in early versions of Delphi, I learnt never to use the with statement under any circumstance, nestable or not.debugging bugs? what debugging bugs? The problem with the "with" statement, as far as I understand it, was one of scope, if it was ever bug it was in our ability to comprehend not the with statement.
That is so ingrained in me now that I suspect I would never use them even if they are fixed. But out of interest, do they operate in a bug free manner in Lazarus/FPC nowadays?
{This is also a case where my new signature applies..}what happened to the danish language? O:-)
Yes, the problem with with is one big bug in programmers: when nested they do not keep track of scope. That's basically all.
In e.g. Python this is less of a problem, because the scope is immediately clear.
Yes, the problem with with is one big bug in programmers: when nested they do not keep track of scope. That's basically all.
In e.g. Python this is less of a problem, because the scope is immediately clear.
I realized that you(and others) are probably not aware that a WITH in Python and FreePascal have completely different semantics.
In Object Pascal WITH is just a syntactic "sugar", and it's controversial, whether it increases readability or on the contrary.
In Python WITH is a syntax for Context Managers(an interface), it does not allow omission of instance names.
That's what I demoed as a possible implementation in Object Pascal, but called USING statement.
A more fundamental construct.
I'm still evaluating FreePascal(a couple of years), but it's not a short way because I come from a GNU/Linux environment, and use Emacs exclusively.
Uhhmmmmm, NO. It has the exact same design purpose. Only in Python it is easier to spot scoping. Because it is Python. Indentation, silly.... <grumpy >:D>
I don't know much about Python, but I think what AlexK said about 'with', is this one:
http://effbot.org/zone/python-with-statement.htm
I can't understand it, that because I never learned Python. So, I'll let more experienced seniors to decide it is good or not.
But if someone want to suggest new features, perhaps (s)he should read this page first:
http://wiki.freepascal.org/Modernised_Pascal
debugging bugs? what debugging bugs? The problem with the "with" statement, as far as I understand it, was one of scope, if it was ever bug it was in our ability to comprehend not the with statement.
Can someone show me the code that contains 'with' bug in free pascal? I use 'with' properly and I found that it's not only makes you less typing but also the code becomes more readable.
Perhaps someone does not understand 'last to first' concept of 'with' statement, which is explained in this page:
https://www.freepascal.org/docs-html/ref/refsu62.html
But that is not bug, right? It is the programmer problem.
Yes... but with is ambiguous. It is not only a programmers problem, but a language design problem...
Anyway, we showed examples that do no necessarily do what the programmer wantsWould some sort of direct reference solve the problem ?
Would some sort of direct reference solve the problem ?That's both the question and the answer isn't it? Or are you being silly, which you are perfectly capable of being not? (That's a complement...)
That's always the problem, speaking identifyers should be or do what the name says.Would some sort of direct reference solve the problem ?That's both the question and the answer isn't it? Or are you being silly, which you are perfectly capable of being not? (That's a complement...)
Case in point: two classes with same field name but different meanings. Case closed.
Anyway, we showed examples that do no necessarily do what the programmer wantsWould some sort of direct reference solve the problem ?
You cannot sanely vote for code like :This is quite readable without using with
...
Is much more readable than the first code. And it's still "safe" no change in a class could destroy that code.
This is quite readable without using with
var ParentId: Some; SubId1: Some; SubId2: Some; begin ParentId := laParentclassspeakingIdentifyer; SubId1 := ParentId.SubClassFunctionSpeakingIdentifyer; SubId2 := ParentId.SubClassFunction2SpeakingIdentifyer; SubId1.PositionSpeed:= SubId1.PositionSpeed + ParentId.SubClassDefaultdataSpeakingIdentifyer.SomeAcceleration; SubId1.PositionSpeed := EnsureRange(SubId1.PositionSpeed, -SubId2.MaximumSpeed, SubId2.MaximumSpeed); SubId1.PositionOfSubclass := SubId1.PositionOfSubclass + SubId1.PositionSpeed; if not InRange(SubId1.PositionOfSubclass, SubId2.MinimumPosition, SubId2.MaximumPosition) then begin SubId1.PositionSpeed:= 0; SubId1.PositionOfSubclass := EnsureRange(SubId1.PositionOfSubclass, SubId2.MinimumPosition, SubId2.MaximumPosition) end end;
If the numbered thing is a bad thing then how about :It's about the ability to define a variable anywhere. With here there is nothing to do.
with l0:=laParentclassspeakingIdentifyer.SubClassFunctionSpeakingIdentifyer do l0.PositionSpeed := 53.1415;
I would prefer to look at it as a temporary alias valid only within scope of with block, not as a new variable. I actually like it, and can imagine very complex with block pretty readable.If the numbered thing is a bad thing then how about :It's about the ability to define a variable anywhere. With here there is nothing to do.
with l0:=laParentclassspeakingIdentifyer.SubClassFunctionSpeakingIdentifyer do l0.PositionSpeed := 53.1415;
It's about the ability to define a variable anywhere. With here there is nothing to do.I would prefer to look at it as a temporary alias valid only within scope of with block, not as a new variable. I actually like it, and can imagine very complex with block pretty readable.
+1 from my side for this syntax idea ::)
Supporting Typecasts could be usefull:What strange people. Instead of pressing Ctrl + Shift + C (at b) after writing b : = Sender as TButton, they prefer to write with and require changing the pascal language for this. Of course it's easier to change the language :D.Silly example, but get my point ;)
with b := Sender as TButton do b.Caption := 'Click';
What strange people. Instead of pressing Ctrl + Shift + C (at b) after writing b : = Sender as TButton, they prefer to write with and require changing the pascal language for this. Of course it's easier to change the language :D.That's not strange, just lazy. With this in mind I believe the expectation is to have b without the need to declare it first while limiting the scope within the with statement. I bet I've seen this in another language before...
In general I'd support this but using your exampleYou replaced 'with' with 'using', so yes it will be freed. But that is not what you intended to do I guess.Shall b be free'd at the end or not ?
using b:= Sender as Tbutton do b.caption := 'Click me!';
You are right, for new code, but what do you do with the tons (gigabytes) of already existing code ? I thought it as an intermediate, to maybe get rid of with in the final coding step.Supporting Typecasts could be usefull:What strange people. Instead of pressing Ctrl + Shift + C (at b) after writing b : = Sender as TButton, they prefer to write with and require changing the pascal language for this. Of course it's easier to change the language :D .Silly example, but get my point ;)
with b := Sender as TButton do b.Caption := 'Click';
Jc99 So you think it's a good idea to have an implicit copy? Hmm.. Think again... Hmmm..You are right, for new code, but what do you do with the tons (gigabytes) of already existing code ? I thought it as an intermediate, to maybe get rid of with in the final coding step.Supporting Typecasts could be usefull:What strange people. Instead of pressing Ctrl + Shift + C (at b) after writing b : = Sender as TButton, they prefer to write with and require changing the pascal language for this. Of course it's easier to change the language :D .Silly example, but get my point ;)
with b := Sender as TButton do b.Caption := 'Click';
Jc99 So you think it's a good idea to have an implicit copy? Hmm.. Think again... Hmmm..No! I think of it as named, dereferenced, scoped pointer ! Otherwise it won't work with records ! And please don't get personal, it's all about the topic !
@jc99The pro is that the programmer would have access to an already existing pointer (as written in the wiki) to avoid ambiguous behavior.
pros and cons!
You started with the cons and give us a nil list of pros.
Replacing "var"/"const" with "with"/"using" is really a good point to abandon this idea.
about scope problems, remember that pascal-derived languages have nested functions and IMO the compiler provide good optimizations.
@Thaddy DWIM leaves place for speculation,
Consider this about with....
function CheckScopeForWith(const value:TObject):Boolean; begin Result := RandomFrom<Boolean>(true); // needs trunk! end;
Error: Operator is not overloaded: "RandomFrom(const {Open} Array Of Double):Double;" < "Boolean"
As long as there is a scoping issue, yes, that's the whole point. It is speculative.,.That's why my first proposal was the (<stack-number>) - Proposal to circumvent name-identifier ambiguity.
Even in some suggestions here like:
with b := Sender as TWhatever do
b.Caption := 'Click';
and TWhatever has a field named "b",.. is plain silly.
@Jc99Have you read the WIKI ?
Pointer? then your "BIG" pro is a total mess because "var"/"const" can provide this with great otimizations on compiler.
Avoid use "with" while you haven't knowledge about of the real purpose.
Disambiguation is a good idea at the first hand, but "with" is not the best way to do it.
Have you actually tried that with a record ?Works fine when i use var and pointers properly
POINTERS, That's your big solution ? Are you sure ?Have you actually tried that with a record ?Works fine when i use var and pointers properly
var lsr: ^TSomerecord; begin SomeStruct[5].SomeRecord.Caption := ''; // Initialization // [...] lsr := @SomeStruct[5].Somerecord; lsr^.Caption := 'Hello Underworld !'; // [...] writeln(SomeStruct[5].Somerecord.Caption);// Are you surprised? end;
By "safe" I understand "auto-free" in the case of exception. FPC (and Delphi too) have "safe" with. The usage is very simple:I mostly use "with" with records.
The big pro to me is that i can _T_ell the _C_ompiler _E_xactly _W_hat _I_ _WantYeah, right, just like with typecasts: "Type casting is the developers way of telling the compiler to "get out of the way! I know what I'm doing"... and the compiler believes you." ~Allen Bauer 2015
I always prefer that over _D_o _W_hat _I_ _M_ean, because as I wrote earlier: that leaves room for speculation and can change over the years.
It also works with interfaces already...By "safe" I understand "auto-free" in the case of exception. FPC (and Delphi too) have "safe" with. The usage is very simple:I mostly use "with" with records.
I mostly use "with" with records and in order to improve performance and readability. You probably know what I mean...It also works with interfaces already...By "safe" I understand "auto-free" in the case of exception. FPC (and Delphi too) have "safe" with. The usage is very simple:I mostly use "with" with records.
Maybe it is time to give the WITH discussion an own thread ?Yes please.
with > null
with object do begin{
something}with object2 do{somethingelse}end;
:-X :P(serious)For me convenience is less important, so i could very much live with it.
If you need a syntax simply a
with l: ttype, y:ttype do
seems fine with me. It is a convenience syntax.
The trouble is that it only fixes accidental clashes when identifiers exist in both "l" and "y", and introduces a new problem, namely that a small mistake (not prefixing with l or y) still might occasionally compile if the identifier exists in the much larger global scope. The accidental fishing in the global scope isn't fixed at all, and this syntax makes it only more likely. (not on misspelling, but also by accidentally omitting the prefix (l,y) )
At least the default WITH automatically overrides the global scope if identifiers match.
A possible, but a bit heavy handed, solution would be to also have to define a prefix for the global scope, and error on any not prefixed value.
with default std, l: ttype, y:ttype, do
But that eats away the convenience factor again.