Lazarus

Free Pascal => General => Topic started by: AlexK on July 09, 2017, 05:38:04 pm

Title: Bounded With
Post by: AlexK on July 09, 2017, 05:38:04 pm
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.

Code: Python  [Select][+][-]
  1. # open returns a "context manager" object that implements methods __enter__ and __exit__, a protocol.
  2. with open("file.txt") as f:
  3.     data = f.read()
  4.     print(data)
  5.  

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.

Code: Pascal  [Select][+][-]
  1. // C# has a "Using" statement, but it merely calls a destructor of used object in the end.
  2. var TheCustomer: Customer;
  3.  
  4. Using TheCustomer to obj do  // "to obj" is optional
  5.     begin
  6.     // do something in a created context here
  7.     obj.SomeMethod; // obj is returned by __enter__
  8.     // compiler calls obj.Destroy here
  9.     end;
  10.  
  11. // Where:
  12. Customer = class     // implements "context manager" protocol for a Using statement
  13.     procedure __enter__;
  14.     function __enter__: Sometype; // returned value assigned "to obj" above
  15.     procedure __exit__;
  16.     procedure __rescue__(ex: Exception);
  17. end;
  18.  
Title: Re: Bounded With
Post by: taazz on July 09, 2017, 05:55:42 pm
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.

Code: Python  [Select][+][-]
  1. # open returns a "context manager" object that implements methods __enter__ and __exit__, a protocol.
  2. with open("file.txt") as f:
  3.     data = f.read()
  4.     print(data)
  5.  

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.

Code: Pascal  [Select][+][-]
  1. // C# has a "Using" statement, but it only calls a destructor of used object in the end.
  2. var TheCustomer: Customer;
  3.  
  4. Using TheCustomer to obj do  // "to obj" is optional
  5.     begin
  6.     // do something in a created context here
  7.     obj.SomeMethod; // obj is returned by __enter__
  8.     // compiler calls obj.Destroy here
  9.     end;
  10.  
  11. // Given:
  12. Customer = class     // implements "context manager" protocol for a Using statement
  13.     procedure __enter__;
  14.     function __enter__: Sometype; // returned value assigned "to obj" above
  15.     procedure __exit__;
  16.     procedure __rescue__(ex: Exception);
  17. end;
  18.  
most of the time they are not needed in pascal eg
Code: Pascal  [Select][+][-]
  1. function Open(const aFilename:TFilename):TFileStream;
  2. begin
  3.    result := tfilestream.create(afilename,fmopenreadwriteorfmshareexclusive);
  4. end;
  5. procedure domytheng;
  6. begin
  7.   with open("MyDataFile.Dat") do
  8.   try
  9.     read(Data, size);
  10.   finally
  11.      free
  12.   end;
  13. end;
  14.  
but 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?
Title: Re: Bounded With
Post by: AlexK on July 09, 2017, 09:39:49 pm
most of the time they are not needed in pascal eg
Code: Pascal  [Select][+][-]
  1. function Open(const aFilename:TFilename):TFileStream;
  2. begin
  3.    result := tfilestream.create(afilename,fmopenreadwriteorfmshareexclusive);
  4. end;
  5. procedure domytheng;
  6. begin
  7.   with open("MyDataFile.Dat") do
  8.   try
  9.     read(Data, size);
  10.   finally
  11.      free
  12.   end;
  13. end;
  14.  
but 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?

Imagine a complex system where you have to create or use some context before calling some of API functions.
You'll create similar try/finally blocks in different parts of your code. That'll take a lot of line, lower readability and maintainability.
What if you have 2 or more logically unrelated contexts that you have to create or use in one function? All they would go into your one try/finally block.

Code: Pascal  [Select][+][-]
  1. Using TheCustomer, SomeOtherObject to name1, OtherHelperContext to name2 do
  2.     begin
  3.     // here needed environment(context) is ensured by these "context managers" above
  4.     name1.someMethod;
  5.     name2.interestingMethod;
  6.     end;
  7.  

All objects in a using statement must implement intrinsic interface:

Code: Pascal  [Select][+][-]
  1. IContextManager = Interface
  2.   // the actual type determined at compilation in class implementation
  3.   // it can be implemented as a procedure in which case "to name1" suffix will not be allowed
  4.   intrinsic __enter__: DeferredType; // RETURNED VALUE ASSIGNED to "name1", "name2" above
  5.   procedure __exit__;
  6.   procedure __rescue__(ex: Exception); // called when "using" statement raises an exception
  7. end;
  8.  

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.

To repeat:
1) Compiler inserts calls to __enter__ implementation when compiling "using" statement, before begin..end, so to speak.
__enter__ implementations can return type that are assigned to name in "using" statement clauses.
2) At the end compiler inserts calls to __exit__ procedures.

If exception occurs, it should call __resque__ procedures.
Title: Re: Bounded With
Post by: bylaardt on July 10, 2017, 04:36:27 am
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.

Code: Python  [Select][+][-]
  1. # open returns a "context manager" object that implements methods __enter__ and __exit__, a protocol.
  2. with open("file.txt") as f:
  3.     data = f.read()
  4.     print(data)
  5.  


What's wrong with
Code: Pascal  [Select][+][-]
  1. f:=open("file.txt")
?
Title: Re: Bounded With
Post by: AlexK on July 10, 2017, 06:22:48 am
What's wrong with
Code: Pascal  [Select][+][-]
  1. f:=open("file.txt")
?

Sorry, but you didn't bother to understand my point. It wasn't only about some techniques of opening a file.
I tend to think the task would require writing another compiler without backward compatibility.

For example, an interface that can declare only the name of a procedural type, without actual types:
Code: Pascal  [Select][+][-]
  1. IContextManager = Interface
  2.   deferred __enter__: FuncOrProcType;
  3.   procedure __exit__;
  4.   procedure __rescue__(ex: Exception);
  5. end;
  6.  

^^Here, the type of __enter__ would be determined by a compiler at an implementation site, in a class. Only the name is enforced by the interface, this opens an ability to create "object protocols".
__enter__ can be implemented as a function or procedure, with any arguments and return types.

Such interface leads to rich semantics that use those required methods in a compiler:
Code: Pascal  [Select][+][-]
  1. Using TheCustomer, SomeOtherObject to name1, OtherHelperContext to name2 do
  2.     begin
  3.     // here needed environment(context) is ensured by these "context managers" above
  4.     name1.someMethod;
  5.     name2.interestingMethod;
  6.     end;
  7.  

A compiler would insert calls to __enter__ methods for each object in "TheCustomer, SomeOtherObject to name1, OtherHelperContext to name2", where name1 and name2 would require that __enter__ is implemented as a function rather than a procedure.
On exit for a using statement compiler would insert calls to __exit__ methods.

More organized memory management.
Quote
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.
Title: Re: Bounded With
Post by: AlexK on July 10, 2017, 08:25:28 am
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.

The programmer is responsible for calling the constructor and the destructor explicitly when using objects.

But it does not relate to what I meant. I took simple semantics in Python as an example and demonstrated how it could possibly be implemented in Object Pascal or some static typed lang.
Title: Re: Bounded With
Post by: Thaddy on July 10, 2017, 12:19:53 pm

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.
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).
A prime example being for.. in.. do, which protects a programmer from accidentally having a range wrong. I think such a feature would not make a language necessarily more baroque.
OTOH, there are some traditional features that should imo never have been there, like allowing with statements nestable. {$modeswitch nowith}

In general I support language features (implemented already  or not) that assist type safety, range and, to a certain extend, also memory management. 
Title: Re: Bounded With
Post by: carl_caulkett on July 12, 2017, 06:39:38 am
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.

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?
Title: Re: Bounded With
Post by: taazz on July 12, 2017, 07:13:36 am
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.

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?
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.
Title: Re: Bounded With
Post by: Thaddy on July 12, 2017, 08:32:21 am
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.
Title: Re: Bounded With
Post by: Handoko on July 12, 2017, 09:03:10 am
I use 'with' a lot, so far never had any problem.
Title: Re: Bounded With
Post by: Thaddy on July 12, 2017, 09:14:53 am
That's because you have a little more talent than others... Try to use it in a team: all hell breaks loose... :P
{This is also a case where my new signature applies..}
Title: Re: Bounded With
Post by: Blestan on July 12, 2017, 09:41:12 am
@thaddy:
Quote
{This is also a case where my new signature applies..}
what happened to the danish language?  O:-)

anyway even if "with" is just a shortcut  and its  a legacy from the dark ages before compiler optimizations and was used to tell the compiler to keep a pointer to something in a register is ok touse it when you know what your are doing
Title: Re: Bounded With
Post by: AlexK on July 12, 2017, 10:00:15 am
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.
Title: Re: Bounded With
Post by: Thaddy on July 12, 2017, 10:06:47 am
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>
Pascal does not know indentation at all. It knows ";". In Python indentation is part of the language. The most important part.
Title: Re: Bounded With
Post by: AlexK on July 12, 2017, 10:19:35 am
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>

You stubbornly refuse to understand, like people that don't even want to hear about anything with a word "Pascal" in it.
WITH in Python represents some kind of short transactions. It's not a shortcut to instance members, but a fundamental thought through construct.

This construct can be explained in terms of an industrial machine, which must execute some procedures in a checked/ensured context:
Code: Python  [Select][+][-]
  1. with SomeMachinePart as ctx1, SimplePreparationDevice, SomeSensor as ctx2:
  2.     # calls some procedures, use ctx1 and ctx2
  3.  
  4. # What it does:
  5. ctx1 = SomeMachinePart.__enter__()
  6. SimplePreparationDevice.__enter__()
  7. ctx2 = SomeSensor.__enter__()
  8. # calls some procedures, use ctx1 and ctx2
  9. SomeSensor.__exit__()
  10. SimplePreparationDevice.__exit__()
  11. SomeMachinePart.__exit__()
  12.  

I have a vague understanding how to implement it in a compiler for a lang with static types.
I know how to implement it in Lisp right away, with a macro.
Title: Re: Bounded With
Post by: Thaddy on July 12, 2017, 10:24:45 am
That's just cluttering syntax. Study language design. I stick to what  wrote. You lack knowledge. You can have an opinion, but please have an informed opinion.
Title: Re: Bounded With
Post by: Handoko on July 12, 2017, 10:39:21 am
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
Title: Re: Bounded With
Post by: marcov on July 12, 2017, 10:45:17 am
A WITH statement with pseudo variables has been implemented by several other languages (since the eighties, nothing new in Python).

VB had a kind of syntax that could prefix identifiers with ..

However, with is in general simply a bad idea. Forget the prefix, and you still accidentally will grab the field name. It mixes scopes, one of which (the active one on the point of the WITH statement) is potentially vast, and the consequences are hard to commit.

That doesn't mean that WITH is diabolical, just don't overuse it, and give it some attention if you must use it. Since the chance on error is fairly small, small scale usage isn't usually a problem. (and static analysis tools could point out clashes)
Title: Re: Bounded With
Post by: AlexK on July 12, 2017, 10:50:55 am
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.

Code: Python  [Select][+][-]
  1. with SomeMachinePart as ctx1, SimplePreparationDevice, SomeSensor as ctx2:
  2.     # calls some procedures, use ctx1 and ctx2
  3.  
  4. # What that statement does:
  5. ctx1 = SomeMachinePart.__enter__()
  6. SimplePreparationDevice.__enter__()
  7. ctx2 = SomeSensor.__enter__()
  8. # calls some procedures, use ctx1 and ctx2
  9. SomeSensor.__exit__()
  10. SimplePreparationDevice.__exit__()
  11. SomeMachinePart.__exit__()
  12.  

It can be used with graphics, OpenGL for example is a state machine.
If any __enter__method or suite raises an Exception, that exception's instance is passed to __exit__methods as arguments.
__enter__ and __exit__ methods are special methods that must be implemented in classes eligible to appear in a WITH statement.
In Object Pascal some kind of IContextManager interface, and I was thinking of compiler logic to implement it in a static lang.
This concept can help organize manual memory management in some general cases, implement transactions(rollback), machine control.

But if someone want to suggest new features, perhaps (s)he should read this page first:
http://wiki.freepascal.org/Modernised_Pascal

Interesting, I'll check it. Wiki format is good too. Python uses systematic process, PEP - Python Enhancement Proposals, each proposal is assigned a number to refer in discussions and "what's new" reports if a PEP was implemented and not rejected. So, each PEP must be formatted as a some kind of "business plan".
Title: Re: Bounded With
Post by: carl_caulkett on July 12, 2017, 10:56:14 am
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.

Check this link https://tinyurl.com/ycarjm4y (Don't worry, you're not going to get RickRolled!)
Title: Re: Bounded With
Post by: Thaddy on July 12, 2017, 10:57:37 am
Or to put it more bluntly: with<something> do <something else that can do something with something>. Now...? Is there any difference? Of course not!
Maybe open a new sub forum on language design. Such things are more fundamental than most of these links warrant.
Title: Re: Bounded With
Post by: Handoko on July 12, 2017, 11:08:50 am
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
Title: Re: Bounded With
Post by: Thaddy on July 12, 2017, 11:12:11 am
Code: Pascal  [Select][+][-]
  1. with label1 do with label2 do caption := 'test';
  2.  
Nuff?? < just slightly grumpy, Handoko  >:D >:D>  O:-)
Title: Re: Bounded With
Post by: marcov on July 12, 2017, 11:17:40 am
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

Code: Pascal  [Select][+][-]
  1. with bla do
  2.   ffield:=3;
  3.  

If the class you are using has a field(and thus in the global scope), but BLA has the same or very similar too, that is dangerous. Any misspelling (like using underscores inbetween, "f" or other prefixes or not) can introduce very hard to find bugs.  This often doesn't happen in the initial code writing, but later when you go back to it and you have a less then complete overview (even more so if you didn't write it yourself to begin with)

It is at least a reason to keep a bit of a lid  on WITH usage, and keep the use cases straight and single (one expression only, no nesting etc)
Title: Re: Bounded With
Post by: Handoko on July 12, 2017, 11:21:06 am
But that is not bug, right? It is the programmer problem.
Title: Re: Bounded With
Post by: marcov on July 12, 2017, 11:24:11 am
But that is not bug, right? It is the programmer problem.

Yes. But the WITH statement is said to invite programmer's errors too much. In such cases, there is always an amount of personal preferences involved, but still that seems to be the consensus.

But as so often (see e.g. GOTO) this creates a whole cult that daemonizes it. Just like with GOTO, just be careful with it. If you program Pascal long enough overuse will bite :-)
Title: Re: Bounded With
Post by: Thaddy on July 12, 2017, 11:25:21 am
Yes... but with is ambiguous. It is not only a programmers problem, but a language design problem...
I seem to agree with Marco again  8-) Are these examples clear?
Title: Re: Bounded With
Post by: marcov on July 12, 2017, 11:26:20 am
Yes... but with is ambiguous. It is not only a programmers problem, but a language design problem...

That is a perfectly valid opinion. (of a cultist :_)
Title: Re: Bounded With
Post by: Thaddy on July 12, 2017, 11:27:36 am
Grrr... Oh well...Point taken... :o
Title: Re: Bounded With
Post by: jc99 on July 12, 2017, 05:35:45 pm
Anyway, we showed examples that do no necessarily do what the programmer wants
Would some sort of direct reference solve the problem ?

Something like :
Code: Text  [Select][+][-]
  1. with A,B,C do
  2.   begin
  3.     (1).aField := aField; // B.aField := C.aField  with a hint "ambiguous identifier, topmost taken" but compilation to stay compatible
  4.     (0).aField := (2).aField; // C.aField := A.aField  compile-error when A has no aField;
  5.   end;
  6.  
Title: Re: Bounded With
Post by: Thaddy on July 12, 2017, 06:05:29 pm
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.
Title: Re: Bounded With
Post by: Handoko on July 12, 2017, 06:32:35 pm
I have my own rules when using 'with':
- Only use 'with' if there are at least 3 fields can be shorten
- If they have same fields on different nested levels, break/remove 1 level

These 2 rules work great so far for me.

Examples:

Code: Pascal  [Select][+][-]
  1. // I won't do this
  2.   with Form1 do
  3.   begin
  4.     Height := 100;
  5.     Width := 200;
  6.   end;
  7.  
  8. // But I do this
  9.   Form1.Height := 100;
  10.   Form1.Width := 200;

Code: Pascal  [Select][+][-]
  1. // I won't do this
  2.   with Form1, Panel1 do
  3.   begin
  4.     Color := Color;
  5.     ShowHint := ShowHint;
  6.     Font := Font;
  7.   end;
  8.  
  9. // But I do this
  10.   with Panel1 do
  11.   begin
  12.     Color := Form1.Color;
  13.     ShowHint := Form1.ShowHint;
  14.     Font := Form1.Font;
  15.   end;
Title: Re: Bounded With
Post by: jc99 on July 12, 2017, 08:53:44 pm
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.
That's always the problem, speaking identifyers should be or do what the name says.

I see the problem of with that the compiler (not the programmer) decides what to reference. And that can change as the involved classes get more complex.
You cannot sanely vote for code like :
Code: Pascal  [Select][+][-]
  1.   laParentclassspeakingIdentifyer.SubClassFunctionSpeakingIdentifyer.PositionSpeed:= laParentclassspeakingIdentifyer.SubClassFunctionSpeakingIdentifyer.PositionSpeed+ laParentclassspeakingIdentifyer.SubClassDefaultdataSpeakingIdentifyer.SomeAcceleration;
  2.   if  laParentclassspeakingIdentifyer.SubClassFunctionSpeakingIdentifyer.PositionSpeed > laParentclassspeakingIdentifyer.SubClassFunction2SpeakingIdentifyer.MaximumSpeed then
  3.     laParentclassspeakingIdentifyer.SubClassFunctionSpeakingIdentifyer.PositionSpeed := laParentclassspeakingIdentifyer.SubClassFunction2SpeakingIdentifyer.MaximumSpeed
  4.   else if  laParentclassspeakingIdentifyer.SubClassFunctionSpeakingIdentifyer.PositionSpeed < -laParentclassspeakingIdentifyer.SubClassFunction2SpeakingIdentifyer.MaximumSpeed then
  5.     laParentclassspeakingIdentifyer.SubClassFunctionSpeakingIdentifyer.PositionSpeed := -laParentclassspeakingIdentifyer.SubClassFunction2SpeakingIdentifyer.MaximumSpeed;
  6.   laParentclassspeakingIdentifyer.SubClassFunctionSpeakingIdentifyer.PositionOfSubclass := laParentclassspeakingIdentifyer.SubClassFunctionSpeakingIdentifyer.PositionOfSubclass + laParentclassspeakingIdentifyer.SubClassFunctionSpeakingIdentifyer.PositionSpeed;
  7.    if laParentclassspeakingIdentifyer.SubClassFunctionSpeakingIdentifyer.PositionOfSubclass > laParentclassspeakingIdentifyer.SubClassFunction2SpeakingIdentifyer.MaximumPosition then  
  8.       begin      
  9.         laParentclassspeakingIdentifyer.SubClassFunctionSpeakingIdentifyer.PositionOfSubclass := laParentclassspeakingIdentifyer.SubClassFunction2SpeakingIdentifyer.MaximumPosition;
  10.         laParentclassspeakingIdentifyer.SubClassFunctionSpeakingIdentifyer.PositionSpeed:= 0;
  11.       end
  12.     else if  laParentclassspeakingIdentifyer.SubClassFunctionSpeakingIdentifyer.PositionOfSubclass < laParentclassspeakingIdentifyer.SubClassFunction2SpeakingIdentifyer.MinimumPosition then  
  13.       begin      
  14.         laParentclassspeakingIdentifyer.SubClassFunctionSpeakingIdentifyer.PositionOfSubclass := laParentclassspeakingIdentifyer.SubClassFunction2SpeakingIdentifyer.MinumumPosition;
  15.         laParentclassspeakingIdentifyer.SubClassFunctionSpeakingIdentifyer.PositionSpeed:= 0;
  16.       end;
  17.  

That code with my suggestion would look like:
Code: Pascal  [Select][+][-]
  1. with laParentclassspeakingIdentifyer.SubClassFunctionSpeakingIdentifyer,
  2.        laParentclassspeakingIdentifyer.SubClassDefaultdataSpeakingIdentifyer,
  3.        laParentclassspeakingIdentifyer.SubClassFunction2SpeakingIdentifyer do
  4.   begin
  5.     (2).PositionSpeed:= (2).PositionSpeed+ (1).SomeAcceleration;
  6.     if  (2).PositionSpeed > (0).MaximumSpeed then
  7.       (2).PositionSpeed := (0).MaximumSpeed
  8.     else if  (2).PositionSpeed < -(0).MaximumSpeed then
  9.       (2).PositionSpeed := -(0).MaximumSpeed;
  10.  
  11.     (2).PositionOfSubclass := (2).PositionOfSubclass + (2).PositionSpeed;
  12.     if (2).PositionOfSubclass > (0).MaximumPosition then  
  13.       begin    
  14.         (2).PositionOfSubclass := (0).MaximumPosition;
  15.         (2).PositionSpeed:= 0;
  16.       end
  17.     else if (2).PositionOfSubclass < (0).MinimumPosition then  
  18.       begin    
  19.         (2).PositionOfSubclass := (0).MinumumPosition;
  20.         (2).PositionSpeed:= 0;
  21.       end;
  22.   end;
  23.  
Is much more readable than the first code. And it's still "safe" no change in a class could destroy that code.

 
Title: Re: Bounded With
Post by: marcov on July 13, 2017, 11:22:35 am
Anyway, we showed examples that do no necessarily do what the programmer wants
Would some sort of direct reference solve the problem ?

No, read my post, all this kind of workarounds (and using numbers is a particular bad one IMHO) make
the construct more flexible but not more safer. It still generates very hard to find errors
if you make a mistake, for trivial benefit.

WITH by definition messes with scopes. That is powerful, and use with care, period.
Title: Re: Bounded With
Post by: ASerge on July 13, 2017, 06:06:10 pm
You cannot sanely vote for code like :
...
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
Code: Pascal  [Select][+][-]
  1. var
  2.   ParentId: Some;
  3.   SubId1: Some;
  4.   SubId2: Some;
  5. begin
  6.   ParentId := laParentclassspeakingIdentifyer;
  7.   SubId1 := ParentId.SubClassFunctionSpeakingIdentifyer;
  8.   SubId2 := ParentId.SubClassFunction2SpeakingIdentifyer;
  9.   SubId1.PositionSpeed:= SubId1.PositionSpeed + ParentId.SubClassDefaultdataSpeakingIdentifyer.SomeAcceleration;
  10.   SubId1.PositionSpeed := EnsureRange(SubId1.PositionSpeed, -SubId2.MaximumSpeed, SubId2.MaximumSpeed);
  11.   SubId1.PositionOfSubclass := SubId1.PositionOfSubclass + SubId1.PositionSpeed;
  12.   if not InRange(SubId1.PositionOfSubclass, SubId2.MinimumPosition, SubId2.MaximumPosition) then
  13.   begin
  14.     SubId1.PositionSpeed:= 0;
  15.     SubId1.PositionOfSubclass := EnsureRange(SubId1.PositionOfSubclass, SubId2.MinimumPosition, SubId2.MaximumPosition)
  16.   end
  17. end;
Title: Re: Bounded With
Post by: jc99 on July 14, 2017, 11:14:49 pm

This is quite readable without using with
Code: Pascal  [Select][+][-]
  1. var
  2.   ParentId: Some;
  3.   SubId1: Some;
  4.   SubId2: Some;
  5. begin
  6.   ParentId := laParentclassspeakingIdentifyer;
  7.   SubId1 := ParentId.SubClassFunctionSpeakingIdentifyer;
  8.   SubId2 := ParentId.SubClassFunction2SpeakingIdentifyer;
  9.   SubId1.PositionSpeed:= SubId1.PositionSpeed + ParentId.SubClassDefaultdataSpeakingIdentifyer.SomeAcceleration;
  10.   SubId1.PositionSpeed := EnsureRange(SubId1.PositionSpeed, -SubId2.MaximumSpeed, SubId2.MaximumSpeed);
  11.   SubId1.PositionOfSubclass := SubId1.PositionOfSubclass + SubId1.PositionSpeed;
  12.   if not InRange(SubId1.PositionOfSubclass, SubId2.MinimumPosition, SubId2.MaximumPosition) then
  13.   begin
  14.     SubId1.PositionSpeed:= 0;
  15.     SubId1.PositionOfSubclass := EnsureRange(SubId1.PositionOfSubclass, SubId2.MinimumPosition, SubId2.MaximumPosition)
  16.   end
  17. end;

If you had written :
Code: Pascal  [Select][+][-]
  1. var
  2.   l0:SubClassFunction2SpeakingIdentifyer;
  3.   l1:TSubClassFunction2SpeakingIdentifyer;
  4.   l2:SubClassFunctionSpeakingIdentifyer;
  5.  
  6. begin
  7.   l2:= laParentclassspeakingIdentifyer.SubClassFunctionSpeakingIdentifyer;
  8.   l1:= laParentclassspeakingIdentifyer.SubClassDefaultdataSpeakingIdentifyer;
  9.   l0:= laParentclassspeakingIdentifyer.SubClassFunction2SpeakingIdentifyer;
  10.  
  11.   l2.PositionSpeed:= l2.PositionSpeed+ l1.SomeAcceleration;
  12.   if  l2.PositionSpeed > l0.MaximumSpeed then
  13.     l2.PositionSpeed := l0.MaximumSpeed
  14.   else if  l2.PositionSpeed < -l0.MaximumSpeed then
  15.     l2.PositionSpeed := -l0.MaximumSpeed;
  16.  
  17.   l2.PositionOfSubclass := l2.PositionOfSubclass + l2.PositionSpeed;
  18.   if l2.PositionOfSubclass > l0.MaximumPosition then  
  19.     begin    
  20.       l2.PositionOfSubclass := l0.MaximumPosition;
  21.       l2.PositionSpeed:= 0;
  22.     end
  23.   else if l2.PositionOfSubclass < l0.MinimumPosition then  
  24.     begin    
  25.       l2.PositionOfSubclass := l0.MinumumPosition;
  26.       l2.PositionSpeed:= 0;
  27.     end;
  28.  
  29. end;
then I would agree with you since that is what the compiler actually does.
Everything else makes the code more readable, which is in general a good thing, but you have to include the math-unit (If I am right).

But if we do what the compiler does I'd vote for "leave it to the compiler"
If the numbered thing is a bad thing then how about :
Code: Pascal  [Select][+][-]
  1. with l0:=laParentclassspeakingIdentifyer.SubClassFunctionSpeakingIdentifyer do
  2.     l0.PositionSpeed := 53.1415;
  3.  
to access the pointer(reference) the compiler generates (read-only) by a local name;
then the only change would be that the := - operation works (like in C) like a function that results the assigned value.
That would also make
Code: Pascal  [Select][+][-]
  1.  a:= b:= 5;
operations possible.[edit] in {$COPERATERS ON}
Title: Re: Bounded With
Post by: ASerge on July 15, 2017, 08:35:10 am
If the numbered thing is a bad thing then how about :
Code: Pascal  [Select][+][-]
  1. with l0:=laParentclassspeakingIdentifyer.SubClassFunctionSpeakingIdentifyer do
  2.     l0.PositionSpeed := 53.1415;
  3.  
It's about the ability to define a variable anywhere. With here there is nothing to do.
Title: Re: Bounded With
Post by: avra on July 15, 2017, 10:52:25 am
If the numbered thing is a bad thing then how about :
Code: Pascal  [Select][+][-]
  1. with l0:=laParentclassspeakingIdentifyer.SubClassFunctionSpeakingIdentifyer do
  2.     l0.PositionSpeed := 53.1415;
  3.  
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  ::)
Title: Re: Bounded With
Post by: AlexK on July 15, 2017, 06:53:44 pm
As I understand there's no a pointer to function type in Object Pascal.

Compiles, fatal runtime error, segmentation fault:

Code: Pascal  [Select][+][-]
  1. type
  2.   TFuncNoArgsString = function(): String; PTFuncNoArgsString = ^TFuncNoArgsString;
  3.  
  4. function Hello: String; begin
  5.   Hello := 'Hello There';
  6. end;
  7.  
  8. procedure Take(f: PTFuncNoArgsString); begin
  9.   WriteLn( f^() );
  10. end;
  11.  
  12. begin
  13.   Take(PTFuncNoArgsString(@Hello));
  14. end.
  15.  
Title: Re: Bounded With
Post by: Turbonobo on July 15, 2017, 07:07:34 pm
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  ::)

I considered 'with' to be evil before  :(
But this temporary alias thing isn't.  :)
Supporting Typecasts could be usefull:
Code: Pascal  [Select][+][-]
  1. with b := Sender as TButton do
  2.     b.Caption := 'Click';
  3.  
Silly example, but get my point   ;)

Would anyone consider adding a 'using' statement?
So this:
Code: Pascal  [Select][+][-]
  1. o := TObject.Create;
  2. try
  3.   //do something with o
  4. finally
  5.   o.free;
  6. end;
  7.  
could be replaced by this:
Code: Pascal  [Select][+][-]
  1. using o := TObject.Create do
  2. begin
  3.   //do something with o
  4. end; //auto free o when out of scope
  5.  
Maybe even something like this instead of multiple nested try finally's:
Code: Pascal  [Select][+][-]
  1. using o := TObject.Create;  b := TOtherObject.Create do
  2. begin
  3.   //do something with o and b;
  4. end; //auto free o and b when out of scope
  5.  
Or use a class TLock that enters a critical section in his constructor and leaves in his destructor
Code: Pascal  [Select][+][-]
  1. //using a helper function lock(s: TCriticalsection) : TLock that wraps the constructor of TLock:
  2. using lock(MyCriticalSection) do
  3. begin
  4.   //within critical section
  5. end; //auto free TLock and unlock criticalsection
  6.  
Title: Re: Bounded With
Post by: jc99 on July 15, 2017, 10:10:29 pm
In general I'd support this but using your example
Code: Pascal  [Select][+][-]
  1. using b:= Sender as Tbutton do
  2.   b.caption := 'Click me!';
  3.  
Shall b be free'd at the end or not ?
Title: Re: Bounded With
Post by: ASerge on July 15, 2017, 11:59:48 pm
Supporting Typecasts could be usefull:
Code: Pascal  [Select][+][-]
  1. with b := Sender as TButton do
  2.     b.Caption := 'Click';
  3.  
Silly example, but get my point   ;)
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.
Title: Re: Bounded With
Post by: Leledumbo on July 16, 2017, 12:24:10 am
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...
Title: Re: Bounded With
Post by: Turbonobo on July 16, 2017, 10:23:37 am
In general I'd support this but using your example
Code: Pascal  [Select][+][-]
  1. using b:= Sender as Tbutton do
  2.   b.caption := 'Click me!';
  3.  
Shall b be free'd at the end or not ?
You replaced 'with' with 'using', so yes it will be freed. But that is not what you intended to do I guess.
My example was slightly different, it used 'with'.
I see them as two different things:
'with' would still be the simple and lazy alias thing, like a const parameter variable that is only accessible from within the scope of a procedure and cannot be assigned to.

But this kind of 'with' just reminded me of something ... the using statement in C#:
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement (https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement)
It is designed for objects implementing the IDisposable interface.
But it could be usefull to have it in Object Pascal too, to ensure objects are getting freed once out of scope.
(and maybe try to call Dispose when using an interface instead of an object)

Code: Pascal  [Select][+][-]
  1. //technically this would be the shorthand equivalent:
  2. using o := TObject.Create do
  3. begin
  4.   //do something with o
  5. end;
  6.  
  7. //to these inline procedures:
  8.  
  9. //one for properly freeing:
  10. procedure using(o: TObject); Inline;
  11. begin
  12.   try
  13.     using_Inner_scope(o);
  14.   finally
  15.     o.free;
  16.   end;
  17. end;
  18.  
  19. //the inner scope of the using statement:
  20. //o is like a const parameter.
  21. procedure using_Inner_scope(const o: TObject); Inline;
  22. begin
  23.     //do something with o;
  24. end;
  25.  
  26. using (TObject.Create);
  27.  
I used two inner procedures because freeing a const variable is not possible I think.

The new 'with' would just be (got to admit it  :D) a lazy shorthand, but 'using' would be a lot more usefull:
Pro's :
  - more readable, cleaner, shorter code.
  - encourages safer coding: programmers are using try finally implicitly and mistakes with nested try finally's are avoided.
  - less verbose, but fits well into the syntax.
  - you could wrap things like beginning/ending critical sections (or anything that needs a try finally) in the constructor and destructor of a class and enforce a 'pattern' (1)
  - ...
Con's :
  - maybe it wil encourages some programmers to write long procedures instead of splitting them up in reusable functions/procedures.
  - the difference between 'with' and 'using' could be confusing and programmers could accidently mix them up, resulting in accidently freeing objects or memory leaks.
  - (1) could be a disadvantage too because it causes some overhead, but no-one forces you to do this.

Recently I saw this "genius"  %) shorthand in production delphi code:
Code: Pascal  [Select][+][-]
  1. with TObject.Create do
  2. begin
  3.   //do something with the object...
  4.   free;
  5. end;
  6.  
So wrong on so many levels  :o, the person who wrote this NEEDS the using statement  :D
Title: Re: Bounded With
Post by: jc99 on July 16, 2017, 09:22:13 pm
Supporting Typecasts could be usefull:
Code: Pascal  [Select][+][-]
  1. with b := Sender as TButton do
  2.     b.Caption := 'Click';
  3.  
Silly example, but get my point   ;)
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 .

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.
Title: Re: Bounded With
Post by: Thaddy on July 16, 2017, 10:32:10 pm
Supporting Typecasts could be usefull:
Code: Pascal  [Select][+][-]
  1. with b := Sender as TButton do
  2.     b.Caption := 'Click';
  3.  
Silly example, but get my point   ;)
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 .

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.
Jc99 So you think it's a good idea to have an implicit copy? Hmm.. Think again... Hmmm..
Title: Re: Bounded With
Post by: jc99 on July 17, 2017, 12:11:01 am
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 !
BTW: Creating a variable with  Ctrl + Shift + C won't work with records too.

[Edit]
There is only one argument against the "NewWith-proposal" for me (but it's a very big one): It's not Delphi compatible !
Title: Re: Bounded With
Post by: bylaardt on July 17, 2017, 03:04:49 am
@jc99

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.
Title: Re: Bounded With
Post by: Thaddy on July 17, 2017, 08:47:05 am
Consider this about with....
Code: Pascal  [Select][+][-]
  1. {$macro on}{$Define dwim:=with}
https://en.wikipedia.org/wiki/DWIM

 >:D :'(
[edit] or
Code: Pascal  [Select][+][-]
  1. uses
  2.   classes,sysutils, math;
  3.  
  4. type
  5.   ESomebodyUsedWithException = class(Exception);
  6.  
  7. function CheckScopeForWith(const value:TObject):Boolean;  
  8. begin
  9.   Result := RandomFrom<Boolean>(true); // needs trunk!
  10. end;
  11.  
  12. function &with(const value:TObject):Tobject;
  13. begin
  14.    Result := value;
  15.   if CheckScopeForWith(value) then
  16.     Raise ESomebodyUsedWithException.Create('Back to school, with statement may be ambiguous here...or not, dunno, raised it anyway...')
  17.  end;
   
Title: Re: Bounded With
Post by: jc99 on July 17, 2017, 11:22:20 am
@jc99

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.
The pro is that the programmer would have access to an already existing pointer (as written in the wiki) to avoid ambiguous behavior.
For me having information and less ambiguity is a very BIG pro (sorry for not stating this so explicit here in the first place, i thought anybody with more than hobby programming experience would instantly see that.)

@Thaddy DWIM leaves place for speculation, it's a more TCEWIW-approach.
nobody forces you to use with, so please vice versa don't force anybody else not to ...
Title: Re: Bounded With
Post by: Thaddy on July 17, 2017, 12:09:58 pm
@Thaddy DWIM leaves place for speculation,

As long as there is a scoping issue, yes, that's the whole point. It is speculative.,.
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.

In general I see just suggestions that require *more* typing to circumvent *less* typing that "with" was introduced for.
As far as I am concerned that is bad language design. We have perfectly readable block-scoping already.
I am not against the use of "with" perse, I am against using it without thought. Usually programmers do not think...Only when the debugger (or a crash... more likely) forces them to do so..
And computer language design is simply based around that concept: programmers do not think, they try and see what happens...

That also means that language features that *require* thought by implication should be banned from a well designed language....

We are all a lot more stupid than we think... :o Otherwise, why would only programmers need a structured language? Now think about that: we are morons..
Title: Re: Bounded With
Post by: bylaardt on July 17, 2017, 04:46:44 pm
@Jc99
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.
Title: Re: Bounded With
Post by: bytebites on July 17, 2017, 06:18:59 pm
Consider this about with....
Code: Pascal  [Select][+][-]
  1.  
  2. function CheckScopeForWith(const value:TObject):Boolean;  
  3. begin
  4.   Result := RandomFrom<Boolean>(true); // needs trunk!
  5. end;
  6.  
  7.  


Which trunk compiles that?
Quote from: compiler says
Error: Operator is not overloaded: "RandomFrom(const {Open} Array Of Double):Double;" < "Boolean"
Title: Re: Bounded With
Post by: Thaddy on July 17, 2017, 06:20:35 pm
Since last friday  :D I wrote it! It is in math.pas. Above syntax is of course also {$mode delphi} but it also works in {$mode objfpc} if you care to type "specialize" a lot....
Small example:
Code: Pascal  [Select][+][-]
  1. program testrandomfrom;
  2. {$mode delphi}
  3. uses math,sysutils;
  4. var
  5.   i:integer;
  6.   a:array[0..99] of string;
  7. begin
  8.   for i :=0 to 99 do
  9.     a[i] := IntToStr(i);
  10.   for i :=1 to 100 do
  11.   begin
  12.     write(RandomFrom<string>(a):4);
  13.     if i mod 10 = 0 then writeln;
  14.   end;
  15.   readln;
  16. end.
Title: Re: Bounded With
Post by: jc99 on July 17, 2017, 11:12:50 pm
As long as there is a scoping issue, yes, that's the whole point. It is speculative.,.
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.
That's why my first proposal was the (<stack-number>) - Proposal to circumvent name-identifier ambiguity.
@Jc99
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 read the WIKI ?
Have you actually tried that with a record ?

Code: Pascal  [Select][+][-]
  1. var lsr=TSomerecord;
  2.      
  3. begin
  4.    SomeStruct[5].Somerecord.Caption := '' // Initialization
  5.    // [...]
  6.    lsr := SomeStruct[5].Somerecord;
  7.    lsr.Caption := 'Hello Underworld !';
  8.    // [...]
  9.    writeln(SomeStruct[5].Somerecord.Caption);//Suprise
  10. end.
  11.  
vs.
Code: Pascal  [Select][+][-]
  1. begin
  2.    SomeStruct[5].Somerecord.Caption := '' // Initialization
  3.    // [...]
  4.    with {lsr :=} SomeStruct[5].Somerecord do
  5.       {lsr.} Caption := 'Hello World !';
  6.    // [...]
  7.    writeln(SomeStruct[5].Somerecord.Caption);//No Suprise
  8. end.
  9.  

[EDIT]
 To make it clear:
The big pro to me is that i can _T_ell the _C_ompiler _E_xactly _W_hat _I_ _Want
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.

Title: Re: Bounded With
Post by: bylaardt on July 18, 2017, 12:13:12 am
Have you actually tried that with a record ?
Works fine when i use var and pointers properly
Code: Pascal  [Select][+][-]
  1. var
  2.   lsr: ^TSomerecord;  
  3. begin
  4.    SomeStruct[5].SomeRecord.Caption := ''; // Initialization
  5.    // [...]
  6.    lsr := @SomeStruct[5].Somerecord;
  7.    lsr^.Caption := 'Hello Underworld !';
  8.    // [...]
  9.    writeln(SomeStruct[5].Somerecord.Caption);// Are you surprised?
  10. end;
  11.  
Title: Re: Bounded With
Post by: jc99 on July 18, 2017, 12:54:22 am
Have you actually tried that with a record ?
Works fine when i use var and pointers properly
Code: Pascal  [Select][+][-]
  1. var
  2.   lsr: ^TSomerecord;  
  3. begin
  4.    SomeStruct[5].SomeRecord.Caption := ''; // Initialization
  5.    // [...]
  6.    lsr := @SomeStruct[5].Somerecord;
  7.    lsr^.Caption := 'Hello Underworld !';
  8.    // [...]
  9.    writeln(SomeStruct[5].Somerecord.Caption);// Are you surprised?
  10. end;
  11.  
POINTERS, That's your big solution ? Are you sure ?
So when writing code you first have distinguish, is it a record or maybe a class, or an object or maybe an array or a generic or is it something else, and what code do I have to use for that specific construct ?
Don't you think that that's a little archaic, when with can provide such an elegant solution ? 

BTW I am not suprised, this looks like code I've written 25 years ago, and I had hoped those times where long gone ...
The topic is about the future of free pascal, but this comes from the "dark"-ages 
Title: Re: Bounded With
Post by: bylaardt on July 18, 2017, 04:44:17 am
Okay. I understand it's not elegant enought for you because is old fashion.
{sarcasm=On}
Just like sex is dirty, obscene and come from a long, long ago tradition of reprodution. I Know! Sex is for "animals"! But in vitro fertilization is better, because you can choose eye color and discard all other embryos. New Fashion!
{sarcasm=Off}
You can do it, is not ambigous and you can be sure this is a pointer. This is the real proposal of strongly typed language.

I know I can't change your opinion and I'll still waiting for your last rejoinder to close this dialectic. I am happy to participate in this interchange of ideas. Thanks.
Title: Re: Bounded With
Post by: mse on July 18, 2017, 07:44:51 am
@jc99:
Give up, FPC never will have a safe "with" statement unless Delphi introduces it. It has been discussed so many times without result. There is even an ancient Pascal compiler which has a save with statement, but FPC - nope.
https://www.mail-archive.com/fpc-pascal%40lists.freepascal.org/msg37615.html

MSElang has it BTW. MSElang also has the unification of "records", "objects" and "classes" which has been requested in another thread.

Title: Re: Bounded With
Post by: hnb on July 18, 2017, 08:40:25 am
By "safe" I understand "auto-free" in the case of exception. FPC (and Delphi too) have "safe" with. The usage is very simple:

Code: Pascal  [Select][+][-]
  1. uses
  2.   SynCommons; // yup. mORMot
  3.  
  4. {...}
  5.  
  6. var
  7.   f: TMyObject;
  8. begin
  9.   with TAutoFree.One(f, TMyObject.Create), f do
  10.   begin
  11.     f.foo := 'some';
  12.     {... unsafe code ...}
  13.   end;
  14.  
Title: Re: Bounded With
Post by: marcov on July 18, 2017, 08:52:48 am
Maybe it is time to give the WITH discussion an own thread ?
Title: Re: Bounded With
Post by: mse on July 18, 2017, 09:05:43 am
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.

Title: Re: Bounded With
Post by: Thaddy on July 18, 2017, 09:05:55 am
The big pro to me is that i can _T_ell the _C_ompiler _E_xactly _W_hat _I_ _Want
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.
Yeah, 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
Title: Re: Bounded With
Post by: Thaddy on July 18, 2017, 09:07:19 am
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.
It also works with interfaces already...
Title: Re: Bounded With
Post by: mse on July 18, 2017, 09:17:01 am
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.
It also works with interfaces already...
I mostly use "with" with records and in order to improve performance and readability. You probably know what I mean...
Title: Re: Bounded With
Post by: Ñuño_Martínez on July 18, 2017, 10:11:32 am
Maybe it is time to give the WITH discussion an own thread ?
Yes please.
Title: Re: Bounded With
Post by: Thaddy on July 18, 2017, 10:16:11 am
Yes plz
Code: [Select]
with > null
Title: Re: Bounded With
Post by: tr_escape on July 18, 2017, 10:50:47 am
So the topic is moved I tried some codes for learning of with statement:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   btn : TButton;
  4.   frm : TForm;
  5. begin
  6.   btn := Button1;
  7.   frm := Form1;
  8.   with btn,frm do
  9.   begin
  10.     btn.Caption:='Btn.Test';
  11.     frm.Caption:='frm.Test';
  12.     Caption:='frm is already in with';
  13.   end;
  14. end;

But if you need to changes about with behaviour what about this format:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   btn : TButton;
  4.   frm : TForm;
  5. begin
  6.   with (btn as Button1),
  7.           (frm as Form1) do
  8.   begin
  9.     btn.Caption:='Btn.Test';
  10.     frm.Caption:='frm.Test';
  11.     Caption:='frm is already in with';
  12.   end;
  13. end;
  14.  

But maybe the behaviour should work as::

Code: Pascal  [Select][+][-]
  1.  
  2.  with [Label1,Button1,Form1],
  3.           (xfrm as Form2) do
  4.   begin
  5.     Caption:='all captions changed!';
  6.     xfrm.caption := 'xform caption';
  7.   end;
  8.  

Just an idea.
Title: Re: Bounded With
Post by: Thaddy on July 18, 2017, 11:05:57 am
Just an idea  :D
Code: [Select]
with object do begin{
something}with object2 do{somethingelse}end;
:-X :P

Curly brackets seem the way to go to define scope...
Title: Re: Bounded With
Post by: marcov on July 18, 2017, 11:14:50 am
(serious)

If you need a syntax simply a

Code: Pascal  [Select][+][-]
  1.  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.

Code: Pascal  [Select][+][-]
  1.  with default std, l: ttype, y:ttype,   do

But that eats away the convenience factor again.
Title: Re: Bounded With
Post by: Thaddy on July 18, 2017, 12:39:02 pm
Yes. Serious. I mentioned that already. "with" is short notation. All suggested alternatives that are scope-safe make notation longer. Which is useless if the alternatives are better. This is a 30+ year discussion. Python got it right because of some very clever whitespace features that will never be available in Pascal (Pascal doesn't know whitespace, it skips it) . (Of course Python's roots are Dutch, 51.7974636,5.4325547,11, not Danish or Swiss :D )
Title: Re: Bounded With
Post by: jc99 on July 19, 2017, 09:18:51 pm
(serious)

If you need a syntax simply a

Code: Pascal  [Select][+][-]
  1.  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.

Code: Pascal  [Select][+][-]
  1.  with default std, l: ttype, y:ttype,   do

But that eats away the convenience factor again.
For me convenience is less important, so i could very much live with it.
I also agree with mse to wait until delphi introduces a safe with statement (probably never).
TinyPortal © 2005-2018