* * *

Author Topic: Bounded With  (Read 1700 times)

jc99

  • Hero Member
  • *****
  • Posts: 516
    • My private Site
Re: Bounded With
« Reply #30 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.  
OS: Win XP x64, Win 7, Win 7 x64, Win 10, Win 10 x64, Suse Linux 13.2
Laz: 1.2 - 1.6.4, 1.8rc3
https://github.com/joecare99/public
'~|    /''
,_|oe \_,are

Thaddy

  • Hero Member
  • *****
  • Posts: 4617
Re: Bounded With
« Reply #31 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.
« Last Edit: July 12, 2017, 06:07:51 pm by Thaddy »
"Logically, no number of positive outcomes at the level of experimental testing can confirm a scientific theory, but a single counterexample is logically decisive."

Handoko

  • Hero Member
  • *****
  • Posts: 1724
  • My goal: build my own game engine using Lazarus
Re: Bounded With
« Reply #32 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;

jc99

  • Hero Member
  • *****
  • Posts: 516
    • My private Site
Re: Bounded With
« Reply #33 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.

 
« Last Edit: July 12, 2017, 08:57:31 pm by jc99 »
OS: Win XP x64, Win 7, Win 7 x64, Win 10, Win 10 x64, Suse Linux 13.2
Laz: 1.2 - 1.6.4, 1.8rc3
https://github.com/joecare99/public
'~|    /''
,_|oe \_,are

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 5807
Re: Bounded With
« Reply #34 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.

ASerge

  • Sr. Member
  • ****
  • Posts: 452
Re: Bounded With
« Reply #35 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;

jc99

  • Hero Member
  • *****
  • Posts: 516
    • My private Site
Re: Bounded With
« Reply #36 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}
« Last Edit: July 15, 2017, 01:49:01 am by jc99 »
OS: Win XP x64, Win 7, Win 7 x64, Win 10, Win 10 x64, Suse Linux 13.2
Laz: 1.2 - 1.6.4, 1.8rc3
https://github.com/joecare99/public
'~|    /''
,_|oe \_,are

ASerge

  • Sr. Member
  • ****
  • Posts: 452
Re: Bounded With
« Reply #37 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.

avra

  • Hero Member
  • *****
  • Posts: 1140
    • Additional info
Re: Bounded With
« Reply #38 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  ::)
ct2laz - Easily convert components and projects between Lazarus and CodeTyphon

AlexK

  • Jr. Member
  • **
  • Posts: 55
Re: Bounded With
« Reply #39 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.  
« Last Edit: July 15, 2017, 06:55:50 pm by AlexK »

Turbonobo

  • New member
  • *
  • Posts: 23
Re: Bounded With
« Reply #40 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.  
« Last Edit: July 15, 2017, 07:27:23 pm by Turbonobo »

jc99

  • Hero Member
  • *****
  • Posts: 516
    • My private Site
Re: Bounded With
« Reply #41 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 ?
OS: Win XP x64, Win 7, Win 7 x64, Win 10, Win 10 x64, Suse Linux 13.2
Laz: 1.2 - 1.6.4, 1.8rc3
https://github.com/joecare99/public
'~|    /''
,_|oe \_,are

ASerge

  • Sr. Member
  • ****
  • Posts: 452
Re: Bounded With
« Reply #42 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.

Leledumbo

  • Hero Member
  • *****
  • Posts: 7717
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Bounded With
« Reply #43 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...

Turbonobo

  • New member
  • *
  • Posts: 23
Re: Bounded With
« Reply #44 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
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
« Last Edit: July 16, 2017, 10:26:34 am by Turbonobo »

 

Recent

Get Lazarus at SourceForge.net. Fast, secure and Free Open Source software downloads Open Hub project report for Lazarus