Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-devel / 2017-08

Optimizing unused return values of inline functions

20 messages · 10 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Benito van der Zander

Hi,

why does fpc not remove the calculation of the return value of inline functions, when the return value is unused?

For example

type TUtility = class
   function doSomething: TUtility; inline;
end;
function TUtility.dosomething: TUtility;
begin
    writeln();
    result := self;
end;

adds a mov rax,rdi in the caller function, even if rax is then never used.

{
26 begin
0x00000000004001c0 <+0>: push rbx

27 ut := TUtility.Create;
0x00000000004001c1 <+1>: movabs rsi,0x1
0x00000000004001cb <+11>: lea rdi,[rip+0x2b2fde] # 0x6b31b0 <VMT_$WTFINLINE_$$_TUTILITY>
0x00000000004001d2 <+18>: call 0x411b60
<SYSTEM$_$TOBJECT_$__$$_CREATE$$TOBJECT>
0x00000000004001d7 <+23>: mov rbx,rax

28 ut.dosomething;
0x00000000004001da <+26>: call 0x41bf20 <fpc_get_output> 0x00000000004001df <+31>: mov rdi,rax
0x00000000004001e2 <+34>: call 0x41c100 <fpc_writeln_end> 0x00000000004001e7 <+39>: call 0x416170 <fpc_iocheck> 0x00000000004001ec <+44>: mov rdi,rbx
0x00000000004001ef <+47>: mov rax,rdi
//<----------------------------------------------- here

29 ut.free;
0x00000000004001f2 <+50>: call 0x411cd0
<SYSTEM$_$TOBJECT_$__$$_FREE>

30 end;
0x00000000004001f7 <+55>: pop rbx
0x00000000004001f8 <+56>: ret
}

It is a popular pattern to add result := self; to _every_ method (or result := @self in objects/records), so it can be chained as dosomething().dosomething().dosomething(),.....
but one cannot use it with fpc efficiently, when it inserts too many unnecessary instructions

Best,

Benito

Michael Van Canneyt
to Benito van der Zander
Benito van der Zander wrote 17 lines
Hi, why does fpc not remove the calculation of the return value of inline functions, when the return value is unused? For example type TUtility = class function doSomething: TUtility; inline; end; It is a popular pattern to add result := self; to _every_ method (or result := @self in objects/records), so it can be chained as dosomething().dosomething().dosomething(),..... but one cannot use it with fpc efficiently, when it inserts too many unnecessary instructions

A strange statement.

This pattern is not inherently efficient. Why should it be ?

It's just something that boiled over from other languages and some people see it as a nifty way of writing code.

Michael.

Benito van der Zander
to Michael Van Canneyt

Hi,

This pattern is not inherently efficient. Why should it be ?

It is not efficient, because of the pointless instruction!

Bye,
Benito

Michael Van Canneyt wrote 33 lines
On Sun, 20 Aug 2017, Benito van der Zander wrote: > Hi, > > why does fpc not remove the calculation of the return value of inline > functions, when the return value is unused? > > For example > > type TUtility = class > function doSomething: TUtility; inline; > end; > > > It is a popular pattern to add result := self; to _every_ method (or > result := @self in objects/records), so it can be chained as > dosomething().dosomething().dosomething(),..... > but one cannot use it with fpc efficiently, when it inserts too many > unnecessary instructions A strange statement. This pattern is not inherently efficient. Why should it be ? It's just something that boiled over from other languages and some people see it as a nifty way of writing code. Michael. _______________________________________________ fpc-devel maillist - http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Michael Van Canneyt
to Benito van der Zander
Benito van der Zander wrote 6 lines
Hi, > This pattern is not inherently efficient. Why should it be ? It is not efficient, because of the pointless instruction!

I am not speaking of the current FPC implementation. It may well be that the code is not most optimal.

I am asking, why do you think *this pattern* (of always returning self) should be inherently more efficient ?

Michael.

Ondrej Pokorny
to Michael Van Canneyt
Michael Van Canneyt wrote
I am asking, why do you think *this pattern* (of always returning self) should be inherently more efficient ?

Benito didn't state it is more efficient (than something else). He said it is popular and not optimized in fpc.

Ondrej

Sven Barth
to Michael Van Canneyt: I am not speaking of the current FPC implementation. It may well be that the code is not…
Michael Van Canneyt wrote 17 lines
On Mon, 21 Aug 2017, Benito van der Zander wrote: > Hi, > >> This pattern is not inherently efficient. Why should it be ? > > > It is not efficient, because of the pointless instruction! I am not speaking of the current FPC implementation. It may well be that the code is not most optimal. I am asking, why do you think *this pattern* (of always returning self) should be inherently more efficient ?

The pattern definitely has its uses. E.g. in the user space of our operating system at work we have a StdOutPrinter class that is used like this:

=== code begin ===

StdIO::stdOutPrinter()->out("Helllo World ")->out(42)->out("
")->hex()->out(42)->line();

=== code end ===

Each function returns again the instance that was returned by StdIO::stdOutPrinter().

The whole pattern is called method chaining or fluent interface:
- https://en.wikipedia.org/wiki/Method_chaining
- https://en.wikipedia.org/wiki/Fluent_interface

Regards,
Sven

Marco van de Voort
to Sven Barth

In our previous episode, Sven Barth via fpc-devel said:

Show quoted text 6 lines
> I am asking, why do you think *this pattern* (of always returning self) > should be inherently more efficient ? The pattern definitely has its uses. E.g. in the user space of our operating system at work we have a StdOutPrinter class that is used like this:

No need to look so far, just look at TV/FV dialog construction.

Sven Barth
to Marco van de Voort
Marco van de Voort wrote 9 lines
In our previous episode, Sven Barth via fpc-devel said: >> I am asking, why do you think *this pattern* (of always returning self) >> should be inherently more efficient ? > > The pattern definitely has its uses. E.g. in the user space of our > operating system at work we have a StdOutPrinter class that is used like > this: No need to look so far, just look at TV/FV dialog construction.

I've never really worked with TV/FV, so I can't use that as an example ^^'

Regards,
Sven

Thaddy de Koning
to Sven Barth: The pattern definitely has its uses. E.g. in the user space of our operating system at…
Show quoted text 43 lines
On 21.08.2017 13:22, Michael Van Canneyt wrote: > > > On Mon, 21 Aug 2017, Benito van der Zander wrote: > >> Hi, >> >>> This pattern is not inherently efficient. Why should it be ? >> >> >> It is not efficient, because of the pointless instruction! > > I am not speaking of the current FPC implementation. It may well be that > the > code is not most optimal. > > I am asking, why do you think *this pattern* (of always returning self) > should be inherently more efficient ? The pattern definitely has its uses. E.g. in the user space of our operating system at work we have a StdOutPrinter class that is used like this: === code begin === StdIO::stdOutPrinter()->out("Helllo World ")->out(42)->out(" ")->hex()->out(42)->line(); === code end === Each function returns again the instance that was returned by StdIO::stdOutPrinter(). The whole pattern is called method chaining or fluent interface: - https://en.wikipedia.org/wiki/Method_chaining - https://en.wikipedia.org/wiki/Fluent_interface Regards, Sven _______________________________________________ fpc-devel maillist - http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel

E.g. KOL is based on this (or very close). The core methods always return self.

Michael Van Canneyt
to Thaddy de Koning
Thaddy de Koning wrote 27 lines
> On 21.08.2017 13:22, Michael Van Canneyt wrote: >> >> >> On Mon, 21 Aug 2017, Benito van der Zander wrote: >> >>> Hi, >>> >>>> This pattern is not inherently efficient. Why should it be ? >>> >>> >>> It is not efficient, because of the pointless instruction! >> >> I am not speaking of the current FPC implementation. It may well be that >> the >> code is not most optimal. >> >> I am asking, why do you think *this pattern* (of always returning self) >> should be inherently more efficient ? > > The pattern definitely has its uses. E.g. in the user space of our > operating system at work we have a StdOutPrinter class that is used like > this: > > === code begin === > > StdIO::stdOutPrinter()->out("Helllo World ")->out(42)->out(" > ")->hex()->out(42)->line();

Call me old-fashioned, but I much prefer

   With StdIO::stdOutPrinter() do
     begin
     out("Helllo World ");
     out(42);
     out("");
     hex();
     out(42);
     line();
     end;

I see no point or gain in the "fluent" code.

Michael.

Sven Barth
to Michael Van Canneyt
"Michael Van Canneyt" wrote 21 lines
On Tue, 22 Aug 2017, Thaddy de Koning wrote: >> On 21.08.2017 13:22, Michael Van Canneyt wrote: >>> >>> >>> >>> On Mon, 21 Aug 2017, Benito van der Zander wrote: >>> >>>> Hi, >>>> >>>>> This pattern is not inherently efficient. Why should it be ? >>>> >>>> >>>> >>>> It is not efficient, because of the pointless instruction! >>> >>> >>> I am not speaking of the current FPC implementation. It may well be

that

Show quoted text 30 lines
>>> the >>> code is not most optimal. >>> >>> I am asking, why do you think *this pattern* (of always returning self) >>> should be inherently more efficient ? >> >> >> The pattern definitely has its uses. E.g. in the user space of our >> operating system at work we have a StdOutPrinter class that is used like >> this: >> >> === code begin === >> >> StdIO::stdOutPrinter()->out("Helllo World ")->out(42)->out(" >> ")->hex()->out(42)->line(); Call me old-fashioned, but I much prefer With StdIO::stdOutPrinter() do begin out("Helllo World "); out(42); out(""); hex(); out(42); line(); end; I see no point or gain in the "fluent" code.

First C++ has no with-statement and second I definitely prefer my output to be on one line. :)
Also in other cases fluent interfaces are rather nice to have. Though they also don't force you to be used in that way :) (at least if they really only return Self/This).

Regards,
Sven

Michael Van Canneyt
to Sven Barth: that First C++ has no with-statement and second I definitely prefer my output to be on…
Sven Barth wrote 18 lines
> > > Call me old-fashioned, but I much prefer > > With StdIO::stdOutPrinter() do > begin > out("Helllo World "); > out(42); > out(""); > hex(); > out(42); > line(); > end; > > I see no point or gain in the "fluent" code. First C++ has no with-statement and second I definitely prefer my output to be on one line. :)
    With StdIO::stdOutPrinter() do begin out("Helllo World ");out(42);out("");hex();out(42);line(); end;

;)

Also in other cases fluent interfaces are rather nice to have. Though they also don't force you to be used in that way :) (at least if they really only return Self/This).

I guess it is a matter of style.

Michael.

Michael Van Canneyt
to Kazantsev Alexey: On Tue, 22 Aug 2017 13:15:24 +0200 (CEST) SomeProc(Builder .Build('1') .Build('2')…
Kazantsev Alexey wrote 22 lines
On Tue, 22 Aug 2017 13:15:24 +0200 (CEST) Michael Van Canneyt wrote: > Call me old-fashioned, but I much prefer > > With StdIO::stdOutPrinter() do > begin > out("Helllo World "); > out(42); > out(""); > hex(); > out(42); > line(); > end; > > I see no point or gain in the "fluent" code. SomeProc(Builder .Build('1') .Build('2') .Build('3').Value);

As far as I can see, that's not really different from the example Sven gave me ?

With builder do
   begin
   Build('1');
   Build('2');
   Build('3');
   SomeProc(Value);
   end;

Michael.

Stefan Glienke
to Michael Van Canneyt: Call me old-fashioned, but I much prefer With StdIO::stdOutPrinter() do begin out("Helllo…

Often a fluent API has some grammar described via different interfaces that are implemented by either one (in this case you always return Self) or different classes.

It is not just to chain methods together that you could also write like you did.

Show quoted text 53 lines
On 22 August 2017 at 13:15 Michael Van Canneyt wrote: On Tue, 22 Aug 2017, Thaddy de Koning wrote: >> On 21.08.2017 13:22, Michael Van Canneyt wrote: >>> >>> >>> On Mon, 21 Aug 2017, Benito van der Zander wrote: >>> >>>> Hi, >>>> >>>>> This pattern is not inherently efficient. Why should it be ? >>>> >>>> >>>> It is not efficient, because of the pointless instruction! >>> >>> I am not speaking of the current FPC implementation. It may well be that >>> the >>> code is not most optimal. >>> >>> I am asking, why do you think *this pattern* (of always returning self) >>> should be inherently more efficient ? >> >> The pattern definitely has its uses. E.g. in the user space of our >> operating system at work we have a StdOutPrinter class that is used like >> this: >> >> === code begin === >> >> StdIO::stdOutPrinter()->out("Helllo World ")->out(42)->out(" >> ")->hex()->out(42)->line(); Call me old-fashioned, but I much prefer With StdIO::stdOutPrinter() do begin out("Helllo World "); out(42); out(""); hex(); out(42); line(); end; I see no point or gain in the "fluent" code. Michael. _______________________________________________ fpc-devel maillist - http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Benito van der Zander
to Kazantsev Alexey: On Tue, 22 Aug 2017 13:15:24 +0200 (CEST) SomeProc(Builder .Build('1') .Build('2')…

Hi,,

Show quoted text 5 lines
SomeProc(Builder .Build('1') .Build('2') .Build('3').Value);

That's exactly what I wanted to use it for

And since a string builder is such a low level construct, mostly used for performance improvements, it needs to be fast without additional instructions

Best,
Benito

Kazantsev Alexey wrote 21 lines
On Tue, 22 Aug 2017 13:15:24 +0200 (CEST) Michael Van Canneyt wrote: > Call me old-fashioned, but I much prefer > > With StdIO::stdOutPrinter() do > begin > out("Helllo World "); > out(42); > out(""); > hex(); > out(42); > line(); > end; > > I see no point or gain in the "fluent" code. SomeProc(Builder .Build('1') .Build('2') .Build('3').Value);
Martin Grajcar
to Michael Van Canneyt: Call me old-fashioned, but I much prefer With StdIO::stdOutPrinter() do begin out("Helllo…

On Tue, Aug 22, 2017 at 1:15 PM, Michael Van Canneyt <

Show quoted text 51 lines
wrote: On Tue, 22 Aug 2017, Thaddy de Koning wrote: On 21.08.2017 13:22, Michael Van Canneyt wrote: >> >>> >>> >>> On Mon, 21 Aug 2017, Benito van der Zander wrote: >>> >>> Hi, >>>> >>>> This pattern is not inherently efficient. Why should it be ? >>>>> >>>> >>>> >>>> It is not efficient, because of the pointless instruction! >>>> >>> >>> I am not speaking of the current FPC implementation. It may well be that >>> the >>> code is not most optimal. >>> >>> I am asking, why do you think *this pattern* (of always returning self) >>> should be inherently more efficient ? >>> >> >> The pattern definitely has its uses. E.g. in the user space of our >> operating system at work we have a StdOutPrinter class that is used like >> this: >> >> === code begin === >> >> StdIO::stdOutPrinter()->out("Helllo World ")->out(42)->out(" >> ")->hex()->out(42)->line(); >> > Call me old-fashioned, but I much prefer With StdIO::stdOutPrinter() do begin out("Helllo World "); out(42); out(""); hex(); out(42); line(); end;

This works well, but you can't tell the meaning of any single line, unless you're sure that all the methods are indeed defined in stdOutPrinter. Imagine

With StdIO::stdOutPrinter() do
    begin
    out("Helllo World ");
    out(size());
    ...
    end;

with size() belonging to the enclosing class. Someone adds size() to stdOutPrinter and you're toasted.

I've even seen a nested WITH misuse like

with src do begin
  with dst do begin
     name := firstName + ' ' + lastName;
     amount := ownAmount;
     ...
   end;
end;

which is a terrible and error-prone misuse.

I see no point or gain in the "fluent" code.

- It's as compact as WITH, but it's explicit.
- It can be written in a single line without violating convention.