[fpc-pascal] modeswitch multihelpers precedence problem

Michael Van Canneyt michael at freepascal.org
Tue Mar 10 08:11:21 CET 2020



On Tue, 10 Mar 2020, Anthony Walter via fpc-pascal wrote:

> I started adding {$modeswitch multihelpers} to some of my code and noticed
> a problem. It would seem that the SysUtils unit is defining type helpers
> for the string type and this led me to discover that multiple type helpers
> takes precedence over other helpers in a way that is conflicts with other
> pascal rules.
>
> To demonstrate, if I have MyUnit.pas that defines a string type helper
> with EndsWith() and an IntToStr() function then consider the following code:
>
> program Test;
>
> uses
>  MyUnit, SysUtils;
>
> begin
>  'hello'.EndsWith('lo'); // invokes MyUnit.TStringHelper.EndsWith()
>  IntToStr(12); // invokes SysUtils.IntToStr()
> end.
>
> But if I reverse the uses order:
>
> program Test;
>
> uses
>  SysUtils, MyUnit;
>
> begin
>  'hello'.EndsWith('lo'); // invokes SysUtils.TStringHelper.EndsWith()
>  IntToStr(12); // invokes MyUnit.IntToStr()
> end.
>
> What should happen is that both examples use the function from the last
> unit in the uses clause. Using the example above with "uses SysUtils,
> MyUnit;" the following should happen:
>
>  'hello'.EndsWith('lo'); // invokes MyUnit.TStringHelper.EndsWith()
>  IntToStr(12); // invokes MyUnit.IntToStr()
>
> I know some of you might see this as a small problem, but it's an
> inconstancy that can lead to a situation where the wrong methods will be
> called without being obvious. The standard has long been that when an
> identifier of the same name is is found, pascal will choose to identify the
> name as the one coming from the last matching unit in the uses clause.
> Multiple type helpers should follow this same rule.

I'm inclined to think you found the reason why Embarcadero disallows type
helpers.

A type helper extends a type with some additional methods. Since the
sysutils unit comes first in the uses clause, it is the first to extend the
string type. Then comes the myunit helper, which tries to extend the same
type with the same methods. The compiler sees the first attached method.

I agree the order of the units is relevant, but I think that it is acting
more like unit initialization & class constructor order 
(if viewed as 'attaching methods to type') than like identifier scope 
(if viewed as 'looking for method identifier').

So while I agree it may be confusing, it's not necessarily wrong.

I suppose Sven can shed some light on the matter.

Michael.


More information about the fpc-pascal mailing list