Recent

Author Topic: Pascal feature proposal: begin(syncObj)  (Read 11347 times)

Cooler

  • Newbie
  • Posts: 6
Pascal feature proposal: begin(syncObj)
« on: July 26, 2015, 09:42:27 am »
When you develop a thread-safe code you probably use critical sections (or other sync objects) very often.
So there are TONS of constructions like:
 
Code: [Select]
  EnterCriticalSection(cSect);
  try
   ...
  finally
   LeaveCriticalSection(cSect);
  end;
 
Besides this makes code bulky, it enforces programmer to carefully track where the protection is really needed and where it is redundant.
Wrong decision here causes performance degradation (best case) or sync issues like deadlocks (in worst case).

So my proposal has 2 goals:
- make code cleaner and more readable;
- free programmer from manual optimization (that can lead to severe bugs), which can be done by compiler.

I propose to extend the "begin ... end" brackets construction syntax like this:

Code: [Select]
begin(cSect)
  ...
 end;

which is equivalent to the code example above, where cSect may be an RTL critical section or RTL sync object with Lock()/Unlock() or Enter()/Leave() methods.
The compiler can then optimize this construction and omit synchronization if:
- the code section doesn't reference any non-local variables (unnecessary call),
- the code section is always executed from places already protected by the same sync object (redundant call).
In addition, it can also make 2 routine instances (protected and unprotected) to use each version from appropriate places.
So this syntax makes it much easier to make code thread-safe without headache about overheads and making the code bulky and unreadable.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11445
  • FPC developer.
Re: Pascal feature proposal: begin(syncObj)
« Reply #1 on: July 26, 2015, 10:25:56 am »
Have you looked at http://www.freepascal.org/faq.var#extensionselect   ?

Shorthand notations are generally frowned upon as motivation for language. (unless it is REALLY,REALLY common)

However I have tons of (250kloc) threadsafe code, and maybe have 20 of such constructs because they are generally deep in the business objects, and the construct is autoexpanded by the IDE, so typing is not even the limit.

Cooler

  • Newbie
  • Posts: 6
Re: Pascal feature proposal: begin(syncObj)
« Reply #2 on: July 26, 2015, 10:59:26 pm »
Have you looked at http://www.freepascal.org/faq.var#extensionselect   ?
No, thanks for the info.

Quote
Shorthand notations are generally frowned upon as motivation for language. (unless it is REALLY,REALLY common)
It's not just shorthand, it's about doing less code maintenance work. It's like using dynamic arrays for data instead of manual heap allocation and bothering about memory release - easier to write, easier to read/understand, less chances to make a bug => makes language more attractive and competitive.
Anyway, there are many shorthand notations already supported in the language (with, for..in, automatic reference counting, string operators, implicit string conversions and so on), so it looks a bit strange. The language is evolving. BTW, Objective-C has similar @synchronized directive.

Quote
and the construct is autoexpanded by the IDE, so typing is not even the limit.
Could you please explain this?

BeniBela

  • Hero Member
  • *****
  • Posts: 906
    • homepage
Re: Pascal feature proposal: begin(syncObj)
« Reply #3 on: July 26, 2015, 11:55:57 pm »
That is why I always say  block scoped variables, referenced counted classes and automatic type inference are mandatory features for a language.

Then you could write

Code: [Select]
begin
  var guard := synchronizedSection(cSect);
end;


But for .. in is a tiny step in the right direction.

You can write

Code: [Select]
var temp: boolean;
//begin
  for temp in synchronizedSection(cSect) do begin
   
  end;


with something like

Code: [Select]
type
  TSectionGuardEnumerator = class
  private
    FCurrent: boolean;
    section: PRTLCriticalSection;
  public
    function MoveNext: Boolean;
    property Current: boolean read FCurrent;
    function GetEnumerator: TSectionGuardEnumerator;
    destructor destroy(); override;
  end;
  function synchronizedSection(var section: TRTLCriticalSection): TSectionGuardEnumerator;
  begin
    result := TSectionGuardEnumerator.Create;
    result.section:=@section;
    result.FCurrent := true;
    EnterCriticalsection(section);
  end;

  destructor TSectionGuardEnumerator.destroy;
  begin
    LeaveCriticalsection(section^);
  end;

  function TSectionGuardEnumerator.MoveNext: Boolean;
  begin
    result := Current;
    FCurrent := false;
  end;

  function TSectionGuardEnumerator.GetEnumerator: TSectionGuardEnumerator;
  begin
    result := self;
  end;


Basile B.

  • Guest
Re: Pascal feature proposal: begin(syncObj)
« Reply #4 on: July 27, 2015, 01:52:32 am »
When you develop a thread-safe code you probably use critical sections (or other sync objects) very often.
So there are TONS of constructions like:
 
Code: [Select]
  EnterCriticalSection(cSect);
  try
   ...
  finally
   LeaveCriticalSection(cSect);
  end;
 
Besides this makes code bulky, it enforces programmer to carefully track where the protection is really needed and where it is redundant.
Wrong decision here causes performance degradation (best case) or sync issues like deadlocks (in worst case).

So my proposal has 2 goals:
- make code cleaner and more readable;
- free programmer from manual optimization (that can lead to severe bugs), which can be done by compiler.

I propose to extend the "begin ... end" brackets construction syntax like this:

Code: [Select]
begin(cSect)
  ...
 end;

To make it more versatile (not only dedicated to TCriticalSection, which the compiler doesn't know BTW, it's a library type... ;) ), I'd see more this as an operator that could be overloaded for a particular type, for example:

Code: [Select]
operator begin(Value: TCriticalSection);
begin
  Value.Enter;
end;

operator end(Value: TCriticalSection);
begin
  Value.Release;
end;

Then the compiler could look if the operator overload exists for the variable of the type found within, let's call it, a BeginExpression

Another possible usage:

Code: [Select]
operator begin(var Value: TMemoryStream);
begin
  Value := TMemoryStream.Create;
end;

operator end(var Value: TMemoryStream);
begin
  Value.Free;
end;

The problem is that currently begin is not an expression. It's a terminal token.

Cooler

  • Newbie
  • Posts: 6
Re: Pascal feature proposal: begin(syncObj)
« Reply #5 on: July 27, 2015, 01:34:25 pm »
To make it more versatile (not only dedicated to TCriticalSection, which the compiler doesn't know BTW, it's a library type... ;) ), I'd see more this as an operator that could be overloaded for a particular type, for example:
Without try/finally it's pretty useless (unless end operator is always executed).
Also such generic approach doesn't allow optimization: compiler will always generate code even if it's redundant.

Basile B.

  • Guest
Re: Pascal feature proposal: begin(syncObj)
« Reply #6 on: July 27, 2015, 02:46:37 pm »
Without try/finally it's pretty useless (unless end operator is always executed).
In my idea it has to be always executed. They go in pair. Also at compile time: an error if operator begin is defined without an operator end, even if it's a nullsub.

Leledumbo

  • Hero Member
  • *****
  • Posts: 8757
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Pascal feature proposal: begin(syncObj)
« Reply #7 on: July 27, 2015, 05:59:57 pm »
I kinda like this extension. I've seen an implementation in Active Oberon (it's chapter 3 in the language report), which looks neat and VERY easy to switch a compound statement from synchronous to asynchronous and back.

Basile B.

  • Guest
Re: Pascal feature proposal: begin(syncObj)
« Reply #8 on: July 27, 2015, 07:49:00 pm »
I already see a grammatical conflict:

Code: [Select]
program Project1;
uses classes;
begin(TMemoryStream.Create)        .size := 8;
end.

So parenthesis would not be the best candidates for a begin expression because some valid code could already be typed in a parens pair following the begin.

Leledumbo

  • Hero Member
  • *****
  • Posts: 8757
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Pascal feature proposal: begin(syncObj)
« Reply #9 on: July 28, 2015, 09:14:05 am »
I already see a grammatical conflict:
Though easily solved (well, our parser is hand written), I agree with you. I prefer something distinct, probably using directive syntax, so there would be another directive scope: block, other than existing global and local scope.

nomorelogic

  • Full Member
  • ***
  • Posts: 165
Re: Pascal feature proposal: begin(syncObj)
« Reply #10 on: July 28, 2015, 12:28:28 pm »
i think this is very interesting
http://www.elementscompiler.com/elements/oxygene/language.aspx#parallelism

under "Asynchronous Statements" section you can find this:

Code: [Select]
begin
  …
  async begin
    DoThis();
    DoThat();
  end;
  DoSomethignElse();
  …

and...

Quote
Here, the entire "begin"/"end" block with the calls to DoThis and DoThat will be executed asynchronously, while the current thread continues on to call DoSomethingElse.

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: Pascal feature proposal: begin(syncObj)
« Reply #11 on: July 29, 2015, 06:40:39 pm »
i think this is very interesting
http://www.elementscompiler.com/elements/oxygene/language.aspx#parallelism

under "Asynchronous Statements" section you can find this:

Code: [Select]
begin
  …
  async begin
    DoThis();
    DoThat();
  end;
  DoSomethignElse();
  …

and...

Quote
Here, the entire "begin"/"end" block with the calls to DoThis and DoThat will be executed asynchronously, while the current thread continues on to call DoSomethingElse.
hell no. That is more confusing because being inlined gives the false information that DoSomethingElse will be called after the to dothis dothat is over and farther more why would I need to inline async calls? what do I get out of it? for example I can see the benefit of an OTL library which hides all that thread and synchronization primitives helping you focused on your problem but I don't see anything useful on this.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

nomorelogic

  • Full Member
  • ***
  • Posts: 165
Re: Pascal feature proposal: begin(syncObj)
« Reply #12 on: July 29, 2015, 08:11:05 pm »
hell no. That is more confusing because being inlined gives the false information that DoSomethingElse will be called after the to dothis dothat is over and farther more why would I need to inline async calls? what do I get out of it? for example I can see the benefit of an OTL library which hides all that thread and synchronization primitives helping you focused on your problem but I don't see anything useful on this.

I think keyword "async" serves precisely to eliminate this kind of confusion.
Basically there is not much difference between this asynchronous inline code and: (1) create a thread, (2) run it and (3) do something else in the meantime (no wait for).

I refer, as an example, to a remote soap authentication or run a heavy query against a database (which takes time)  that keeps main thread locked.
To remedy I can create a thread that authenticates or write something like:

Code: [Select]
TForm1.Create (Sender: TObject);
begin
    async Datamodule1.OpenAllNeededTables;
    async Soap1.Authenticate;
    Left:=100;
    Caption:='Hello World!';
end;

or

Code: [Select]
TForm1.Create (Sender: TObject);
begin
    async begin
      Datamodule1.OpenAllNeededTables;
      Soap1.Authenticate;
   end;
    ...
end;

bylaardt

  • Sr. Member
  • ****
  • Posts: 309
Re: Pascal feature proposal: begin(syncObj)
« Reply #13 on: July 29, 2015, 09:59:47 pm »
i agree with taazz: confusing.
what async do?
insert something like a application.processmessages after each instruction at compiler time?

nomorelogic

  • Full Member
  • ***
  • Posts: 165
Re: Pascal feature proposal: begin(syncObj)
« Reply #14 on: July 30, 2015, 03:31:45 pm »
i agree with taazz: confusing.
what async do?
insert something like a application.processmessages after each instruction at compiler time?

async should execute, asynchronously, a single statement or a begin/end block (in a separate thread)
ProcessMessages forces main thread messages to be executed


honestly I think that confusion there is and can be dangerous, in relation to code as:
Code: [Select]
for a:=1 to 100000 do
  async DoSomething();

this code is expected to create 100000 threads: here the damage is greater than the benefit
where the rigth code to write is:

Code: [Select]
async for a:=1 to 100000 do
  DoSomething();

but I think it's still an interesting, easy and powerful approach

 

TinyPortal © 2005-2018