Sign in Join

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

Mailing lists / fpc-devel / 2019-12

C-block reference syntax (blocker for 3.2)

44 messages · 7 people · –

Reply by email Subscribe to this list Your subscription

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

Unknown author

Beforehand, to provide a context, here are some excerpts from private correspondence:

On 11.12.2016 22:00:37 +0300, wrote in

my progress thus far 9) Method reference directives are now allowed: type M = reference to procedure varargs cdecl; DCC-style syntax is used

On 27.06.2017 11:44:40 +0200, Sven Barth wrote in

the syntax for cblock references was selected on purpose to be compatible with the syntax for Delphi style "reference to" method pointers, only with "cdecl" as calling convention.

On 10.02.2018 14:34:42 +0100, Sven Barth wrote in

It seems that anonymous functions do indeed support calling conventions... dang it... I had hoped to use the calling convention as a marker for the difference which is why I told Jonas to implement cblocks this way. But on the other hand I'd say that it is really unusual to use a calling convention with anonymous functions

On 23.08.2019 06:54:21 +0200, Sven Barth wrote in

There isn't much use for "reference to XXX; cdecl;" in the field for normal anonymous functions. Yes, it works, but really, who uses it that way? So the solution is simply to have "reference to XXX; cdecl;" be parsed as a cblock if modeswitch CBLOCKS is set and as a normal anonymous function reference otherwise. This way it can be controlled on a per-unit base.

Counterpoints:
1) In my professional opinion, the current "solution" is a horrible yucky hack: different (albeit similar) entities look exactly the same, and they cannot be used simultaneously.
2) As a compiler developer, my job is to provide orthogonal building blocks and ensure that every conceivable semantically valid combination of them actually works. When one applies reasoning akin to "who uses it that way", they inevitably reduce the power of a language to a subset defined by their often limited understanding of what can and should be possible.
3) My first example back in 2016 intentionally featured a valid use case: CDECL is crucial for VARARGS. (Somehow, not only that case, but the whole point that DCC accepts calling conventions went unnoticed.)

Seeing that introducing this syntax collision was clearly unintentional, I cannot understand the seeming reluctance to remedy it. I have a couple of proposals:
1) Instead of the CDecl directive, use the C directive:

	type M = reference to procedure c;

Pros: Since DCC does not support this MacPas directive, and old MacPas code does not have the REFERENCE TO syntax, there would be no collision whatsoever. Cons: Since C and CDECL are semantically the same, these syntaxes still look confusingly the same:

	type M = reference to procedure cdecl;	// closure
	type M = reference to procedure c;	// C-block

I wonder from where that desire to have the Delphi-like syntax for C-block references came. If it stemmed from the assumption that having the same syntax would simplify the compiler, then we have a solid basis for changing it, because that assumption was wrong. Jonas parses them via procvar_dec, and I parse closure reference types via parse_proc_dec under symtablestack.push(invokable_interface.symtable), and it makes perfect sense since such types /are/ interfaces (to the point that they are directly implementable on classes).
2) Same as (1), but without REFERENCE TO:

	type M = procedure c;

Pros: No collision with DCC. Easy to parse.
Cons: Collision with procedural types in MacPas. Since, presumably, MacPas is for compatibility with legacy code, this collision is less of a problem than the collision with DCC; but a collision nevertheless.
3) Attributes:

	type [CBlock] M = reference to procedure;
	type [CBlock] M = procedure;

Pros: In my book, the most elegant solution.
Cons: Attributes are applied to symbols, not type definitions; which is problematical for nameless type definitions, parsing, and semantics.
4) Distinct syntax, without adding new keywords:

	type M = procedure with var;	// a closure is literally a "procedure with [captured outer] variables"
	type M = procedure with record;	// captured variables are kept in a kind of record
	type M = procedure with out name;	// clever!
	type M = procedure is c;	// meaning "is [a] c[-block]"

5) Distinct syntax with a new keyword:

	type M = procedure cblock;
If there is a consensus that this is a blocker, I am ready to do the work ASAP. provided we select the syntax. Personally, I am inclined towards these three:
	type M = procedure (const N: Integer) with var;
	type M = procedure (const N: Integer) cblock;
	type M = reference to procedure (const N: Integer) c;
Again, in the last case (like with the current collision), the non-existent unified C-block/closure reference parser would not be able to reuse as much existing infrastructure as two separate parsers currently do reuse (but do not coöperate).
(Also, it appears that there is a couple of C-block-related bugs, which I am ready to tackle as well.)
βþ

Reply by email

Michael Van Canneyt
to Unknown author
Show quoted text 9 lines
Beforehand, to provide a context, here are some excerpts from private correspondence: If there is a consensus that this is a blocker, I am ready to do the work ASAP. provided we select the syntax. Personally, I am inclined towards these three: type M = procedure (const N: Integer) with var; type M = procedure (const N: Integer) cblock;

I would go for the last one.
It makes immediatly clear upon reading what it stands for: a reference to a cblock. 'with var' etc. do not make clear what it stands for.

Michael.

Reply by email

Jonas Maebe
to Unknown author: Beforehand, to provide a context, here are some excerpts from private correspondence: On…
3) My first example back in 2016 intentionally featured a valid use case: CDECL is crucial for VARARGS. (Somehow, not only that case, but the whole point that DCC accepts calling conventions went unnoticed.)

I indeed did not know that.

I wonder from where that desire to have the Delphi-like syntax for C-block references came.

It came from the facts that
1) afaik Delphi also allows you to pass plain methods (not sure about plain procedures/functions though) to anonymous function parameters, so inventing a new syntax seemed counterproductive
2) if, over time, someone would implement support for inline anonymous functions (as you are doing now), that support could be added for C-blocks as well without ending up with two different syntaxes for semantically the same thing (just a different runtime/implementation under the hood).

Show quoted text 6 lines
If there is a consensus that this is a blocker, I am ready to do the work ASAP. provided we select the syntax. Personally, I am inclined towards these three: type M = procedure (const N: Integer) with var; type M = procedure (const N: Integer) cblock; type M = reference to procedure (const N: Integer) c;
I would prefer type M = reference to procedure (const N: Integer)
cblock;

It's weird that unlike with plain procvar type declarations, there's no semicolon between the end of the signature and the calling convention modifier though. Or is that merely a Delphi syntax thing?

Jonas

Reply by email

Sven Barth
to Unknown author: Beforehand, to provide a context, here are some excerpts from private correspondence: On…

Am 07.12.2019 um 01:00 schrieb

Show quoted text 44 lines
Beforehand, to provide a context, here are some excerpts from private correspondence: On 11.12.2016 22:00:37 +0300, wrote in > my progress thus far > 9) Method reference directives are now allowed: >     type M = reference to procedure varargs cdecl; > DCC-style syntax is used On 27.06.2017 11:44:40 +0200, Sven Barth wrote in > the syntax for cblock references was selected on purpose to be > compatible with the syntax for Delphi style "reference to" method > pointers, only with "cdecl" as calling convention. On 10.02.2018 14:34:42 +0100, Sven Barth wrote in > It seems that anonymous functions do indeed support calling > conventions... dang it... I had hoped to use the calling convention > as a marker for the difference which is why I told Jonas to implement > cblocks this way. But on the other hand I'd say that it is really > unusual to use a calling convention with anonymous functions On 23.08.2019 06:54:21 +0200, Sven Barth wrote in > There isn't much use for "reference to XXX; cdecl;" in the field for > normal anonymous functions. Yes, it works, but really, who uses it > that way? > So the solution is simply to have "reference to XXX; cdecl;" be > parsed as a cblock if modeswitch CBLOCKS is set and as a normal > anonymous function reference otherwise. This way it can be controlled > on a per-unit base. Counterpoints: 1) In my professional opinion, the current "solution" is a horrible yucky hack: different (albeit similar) entities look exactly the same, and they cannot be used simultaneously. 2) As a compiler developer, my job is to provide orthogonal building blocks and ensure that every conceivable semantically valid combination of them actually works. When one applies reasoning akin to "who uses it that way", they inevitably reduce the power of a language to a subset defined by their often limited understanding of what can and should be possible. 3) My first example back in 2016 intentionally featured a valid use case: CDECL is crucial for VARARGS. (Somehow, not only that case, but the whole point that DCC accepts calling conventions went unnoticed.)

I stand by my point that the combination of anonymous function variables with calling conventions and cblocks occurs very, very seldomly.

1.) CBlocks are only supported on Mac OS X / macOS. 2.) Setting the calling convention for an anonymous function is only really useful for one specific case: simulating a COM/WinRT delegate which is essentially an interface with a single Invoke function (just like how anonymous functions are implemented) using the StdCall calling convention. Thus this would only really be required on Windows. And no, your argument with VarArgs does not count either: one can not access VarArgs parameters inside a Delphi/FPC function (without resorting to assembly). In fact they can only be safely used for external functions in FPC.

So there is no real overlap here. Even if the default calling convention should be set to pocall_cdecl one could check tprocdef.procoptions for po_hascallingconvention to decide this.

But if we want to change this syntax, we should definitely change this now before 3.2 is out of the door.

Am 07.12.2019 um 01:00 schrieb

Show quoted text 5 lines
Jonas parses them via procvar_dec, and I parse closure reference types via parse_proc_dec under symtablestack.push(invokable_interface.symtable), and it makes perfect sense since such types /are/ interfaces (to the point that they are directly implementable on classes).

That is only how they are implemented. In fact you should parse the declaration using procvar_dec (with possible extensions/checks) as well, because that handles procvar specific functionality and from the user's point of view an anonymous function variable is essentially a procvar as well. Only afterwards you create an interface with an appropriate method. I thought I had written you this way back, but for the life of me I can't find that mail anymore...

Regards,
Sven

Reply by email

Sven Barth
to Jonas Maebe: I indeed did not know that. It came from the facts that 1) afaik Delphi also allows you…
Jonas Maebe wrote 13 lines
> If there is a consensus that this is a blocker, I am ready to do the > work ASAP. provided we select the syntax. Personally, I am inclined > towards these three: >     type M = procedure (const N: Integer) with var; >     type M = procedure (const N: Integer) cblock; >     type M = reference to procedure (const N: Integer) c; I would prefer type M = reference to procedure (const N: Integer) cblock; It's weird that unlike with plain procvar type declarations, there's no semicolon between the end of the signature and the calling convention modifier though. Or is that merely a Delphi syntax thing?

I just tested in Delphi: it chokes on the semicolon for reference variables, but allows it for normal proc-/methodvars... *sigh*

I'd say we should allow the semicolon as well so that it is more common with proc- and methodvars (would probably be easier anyway, cause it could then use the normal parse_proc_directives or more importantly procvar_dec as I suggested in the other mail).

Regards,
Sven

Reply by email

Michael Van Canneyt
to Sven Barth
Sven Barth wrote 21 lines
Am 07.12.2019 um 10:28 schrieb Jonas Maebe: > >> If there is a consensus that this is a blocker, I am ready to do the >> work ASAP. provided we select the syntax. Personally, I am inclined >> towards these three: >>     type M = procedure (const N: Integer) with var; >>     type M = procedure (const N: Integer) cblock; >>     type M = reference to procedure (const N: Integer) c; > > I would prefer type M = reference to procedure (const N: Integer) cblock; > > It's weird that unlike with plain procvar type declarations, there's > no semicolon between the end of the signature and the calling > convention modifier though. Or is that merely a Delphi syntax thing? I just tested in Delphi: it chokes on the semicolon for reference variables, but allows it for normal proc-/methodvars... *sigh* I'd say we should allow the semicolon as well so that it is more common with proc- and methodvars (would probably be easier anyway, cause it could then use the normal parse_proc_directives or more importantly procvar_dec as I suggested in the other mail).

I agree. It's more consistent.

Michael.

Reply by email

Unknown author
to Sven Barth: Am 07.12.2019 um 01:00 schrieb I stand by my point that the combination of anonymous…
Sven Barth wrote
I stand by my point that the combination of anonymous function variables with calling conventions and cblocks occurs very, very seldomly.

I am not necessarily disputing that point, I am disputing your design decision, which was misinformed, but you continue to stand by it. My primary point: closures and calling conventions are orthogonal. Even if DCC did not support combining them, I would have implemented the support anyway.

your argument with VarArgs does not count either: one can not access VarArgs parameters inside a Delphi function (without resorting to assembly)

Again, you are misinformed.
I understand that you may not use DCC as much or at all, but you have just indicated in an adjacent email that you do have access to it. You made the original assumption that DCC does not accept calling convention directives on method references without actually checking or asking someone with DCC experience, and, despite me having indicated twice already that VARARGS is acceptable and works, you continue to argue that it does not. Based on what, if not on your vast DCC experience?

So there is no real overlap here.

The "real overlap here" is that, depending on which $MODESWITCH happens to be in effect, the sequence of lexemes

	type M = reference to procedure cdecl;

have different semantics -- constructing different entities that can and should be allowed to coexist, even within a single unit, without the need to toggle $MODESWITCH back and forth.

But if we want to change this syntax, we should definitely change this now before 3.2 is out of the door.

Jonas just said that he "indeed did not know" about the syntax collision. And that baffles me the most. The issue may have gone unnoticed back in 2016, but you were definitely aware of it in 2018. So, back in August, I reasonably assumed that you were presenting the consolidated position of the team. Turns out, you have never brought it to the team, and made that questionable design decision on your own. This warrants a discussion, the one I thought the team already had (hence my overly elaborate plea), and now we are blocking 3.2 at the finish line.

Am 07.12.2019 um 01:00 schrieb > Jonas parses them via procvar_dec, and I parse closure reference types via parse_proc_dec under symtablestack.push(invokable_interface.symtable), and it makes perfect sense since such types /are/ interfaces (to the point that they are directly implementable on classes). you should parse the declaration using procvar_dec (with possible extensions/checks) as well, because that handles procvar specific functionality

But I do not need the "procvar specific functionality". As I said, I need an interface type, thus it makes perfect sense to parse the declaration as a method header and to get almost everything handled "for free".

Only afterwards you create an interface with an appropriate method.

And what do I do with the unneeded procvardef? :)
Again: I am not saying that "the non-existent unified C-block/closure reference parser" would be especially difficult to implement, I have merely pointed out that, implementation-wise, having two separate parsers makes sense since they can fully leverage the existing infrastructure.

βþ

Reply by email

Sven Barth
to Unknown author

Am 07.12.2019 um 14:31 schrieb

Show quoted text 14 lines
> your argument with VarArgs does not count either: one can not access > VarArgs parameters inside a Delphi function (without resorting to > assembly) Again, you are misinformed. I understand that you may not use DCC as much or at all, but you have just indicated in an adjacent email that you do have access to it. You made the original assumption that DCC does not accept calling convention directives on method references without actually checking or asking someone with DCC experience, and, despite me having indicated twice already that VARARGS is acceptable and works, you continue to argue that it does not. Based on what, if not on your vast DCC experience?

I'm not arguing that DCC supports declaring functions with VARARGS directive, but I'm arguing that there is no builtin way to *access* the parameters passed in such a way. Yes, there are hacks (like this one https://stackoverflow.com/questions/298373/how-can-a-function-with-varargs-retrieve-the-contents-of-the-stack ), but this is not guaranteed to work on every platform. Thus FPC explicitely forbids implementing functions that have the varargs modifier (they are okay for external functions and also procedure variables as the later can point to an external function). This will not change with anonymous functions and an anonymous function with varargs modifier will not be allowed anyway.

Show quoted text 22 lines
> So there is no real overlap here. The "real overlap here" is that, depending on which $MODESWITCH happens to be in effect, the sequence of lexemes     type M = reference to procedure cdecl; have different semantics -- constructing different entities that can and should be allowed to coexist, even within a single unit, without the need to toggle $MODESWITCH back and forth. > But if we want to change this syntax, we should definitely change > this now before 3.2 is out of the door. Jonas just said that he "indeed did not know" about the syntax collision. And that baffles me the most. The issue may have gone unnoticed back in 2016, but you were definitely aware of it in 2018. So, back in August, I reasonably assumed that you were presenting the consolidated position of the team. Turns out, you have never brought it to the team, and made that questionable design decision on your own. This warrants a discussion, the one I thought the team already had (hence my overly elaborate plea), and now we are blocking 3.2 at the finish line.

I agree that I should have brought this to the team back then, but I still stand with my opinion. But if Jonas says that should be changed I'll be the last to complain here...

Show quoted text 16 lines
> Am 07.12.2019 um 01:00 schrieb >> Jonas parses them via procvar_dec, and I parse closure reference >> types via parse_proc_dec under >> symtablestack.push(invokable_interface.symtable), and it makes >> perfect sense since such types /are/ interfaces (to the point that >> they are directly implementable on classes). > > you should parse the declaration using procvar_dec (with possible > extensions/checks) as well, because that handles procvar specific > functionality But I do not need the "procvar specific functionality". As I said, I need an interface type, thus it makes perfect sense to parse the declaration as a method header and to get almost everything handled "for free".

You need procvar specific functionality, because you need to restrict the available modifiers to those available for procvars. Even if you would call parse_var_proc_directives instead of parse_proc_directives or parse_object_proc_directives (I don't know what you use right now) the parser internally uses check_proc_directives(false) inside parse_proc_dec and friends thus you'd get unclean handling if someone would use e.g. the "overload" directive which is allowed for interface methods, but not for proc-/methodvars.

Also with Jonas' preferred syntax for the cblocks being "reference to XXX; cblocks;" you need to use procvar_dec anyway.

> Only afterwards you create an interface with an appropriate method. And what do I do with the unneeded procvardef? :)

You extend tprocvardef.create with a doregister parameter (and pass that to the inherited constructor) and set that to False for "reference to" types. You then register it for "cblocks" types and for anonymous function you convert the procvar to an interface method and then free the no longer required procvardef.

Show quoted text 5 lines
Again: I am not saying that "the non-existent unified C-block/closure reference parser" would be especially difficult to implement, I have merely pointed out that, implementation-wise, having two separate parsers makes sense since they can fully leverage the existing infrastructure.

The thing is that you're using the *wrong* infrastructure. parse_proc_dec function is for parsing function/procedure/method declarations and definition heads, but you're parsing something that's in essence a fancy procedure/method variable which is completely independant of it being implemented by an interface. Thus it should be parsed the same way as a procedure/method variable.

Regards,
Sven

Reply by email

Unknown author
to Sven Barth
Sven Barth wrote
I'm arguing that there is no builtin way to *access* the parameters passed in such a way.

You are arguing that /now/, but it is not what you said earlier. You said, verbatim:

one can not access VarArgs parameters inside a Delphi function (without resorting to assembly)

Like I said, this is factually incorrect.

there are hacks

A custom va_list implementation, fully conforming to the ABI and particularities of the compiler, is not necessarily a hack. (In the sense that is not of questionable design, implementation quality, and maintainability.)

but this is not guaranteed to work on every platform.

Where did that requirement of "every platform" suddenly come from? One needs to roll out their own va_list implementations only for the platforms A) that he targets, and B) on which the stock implementation is not provided.

an anonymous function with varargs modifier will not be allowed anyway

Right. FTR, my patch will eventually allow exactly that, and so does DCC already. Or are you still not aware of the latter? For the fourth time: VARARGS is allowed and works with DCC, on both sides, without BASM or ugly hacks, on more than one platform :) Some of them even have stock implementations of va_list, FPC should take a hint.

You need procvar specific functionality, because you need to restrict the available modifiers to those available for procvars.

And if I use the procvardef parser, I, like Jonas, would need to prohibit "OF OBJECT" and "IS NESTED". One extra work for another.

You extend tprocvardef.create with a doregister parameter you convert the procvar to an interface method and then free the no longer required procvardef.

Right. The unnecessary work I am currently avoiding. Since I have not yet submitted that part for review, let us avoid premature pointless discussion.

you're parsing something that's in essence a fancy procedure/method variable which is completely independant of it being implemented by an interface

"Completely independent"?
You do realise that method reference types "being <...> interface[s]" is pretty much a part of the specification? ----------8<----------
type M = reference to procedure (const N: Integer); type C = class (TInterfacedObject, M)

	procedure Invoke(const N: Integer); virtual; abstract;

end;
end.
----------8<----------

βþ

Reply by email

Sven Barth
to Unknown author

Am 07.12.2019 um 22:46 schrieb

Show quoted text 9 lines
On 07.12.2019 21:39, Sven Barth wrote: > I'm arguing that there is no builtin way to *access* the parameters > passed in such a way. You are arguing that /now/, but it is not what you said earlier. You said, verbatim: > one can not access VarArgs parameters inside a Delphi function > (without resorting to assembly) Like I said, this is factually incorrect.

I had forgotten about pointers to the stack area which I got reminded off when I found the link I sent. But that doesn't change that there is no official way to access such parameters.

Show quoted text 14 lines
> there are hacks A custom va_list implementation, fully conforming to the ABI and particularities of the compiler, is not necessarily a hack. (In the sense that is not of questionable design, implementation quality, and maintainability.) > but this is not guaranteed to work on every platform. Where did that requirement of "every platform" suddenly come from? One needs to roll out their own va_list implementations only for the platforms A) that he targets, and B) on which the stock implementation is not provided.

It's to show the restriction of the approach that is shown in the link. While it works on i386-win32 and probably also x86_64-win64 it would fail on e.g. x86_64-linux (or any other x86_64 platform following the Sys V ABI). I give you point A, but B is moot as there is no stock implementation in Delphi for *any* platform.

Show quoted text 9 lines
> an anonymous function with varargs modifier will not be allowed anyway Right. FTR, my patch will eventually allow exactly that, and so does DCC already. Or are you still not aware of the latter? For the fourth time: VARARGS is allowed and works with DCC, on both sides, without BASM or ugly hacks, on more than one platform :) Some of them even have stock implementations of va_list, FPC should take a hint.

But only on i386-win32 and x86_64-win64. On Sys V ABI x86_64 targets there is no way around it, because the arguments are passed in registers, not in the stack area. That's why GCC implements the va[ist functionality using compiler intrinsics instead of macros as is the case on Windows.

And no, your patch WILL NOT allow that. We've consciously decided AGAINST implementing varargs functions in Pascal (see https://wiki.freepascal.org/User_Changes_2.6.0#Array_of_const_parameters_and_cdecl_routines ) and we DO NOT WANT to support this.

So what will be allowed is this:

=== code begin ===

type
   TSomeProc = reference to procedure(aFmt: PChar); cdecl; varargs;

=== code end ===

but not this:

=== code begin ===

var
   proc: TSomeProc;
begin
   proc := procedure(aFmt: PChar) cdecl varargs
     begin
       { do something with aFmt and the variadic arguments }
     end;
end.

=== code end ===

Just as it is for procedure and method variables.

And yes, it makes sense to allow it for one, but to deny it for another, because as TSomeProc is an interface it can be used to interface (no pun intended) with external code that provides such an interface as well (e.g. delegates in COM/WinRT, though I have yet so see a varargs function there...).

For Pascal code there is "array of const" which is better anyway, cause all values contain type information about the passed value. And it works cross platform (which for FPC *is* important).

Show quoted text 6 lines
> You need procvar specific functionality, because you need to restrict > the available modifiers to those available for procvars. And if I use the procvardef parser, I, like Jonas, would need to prohibit "OF OBJECT" and "IS NESTED". One extra work for another.

The code of procvar_dec as it is currently does not forbid it. So that will need to be improved anyway.

Show quoted text 24 lines
> You extend tprocvardef.create with a doregister parameter > you convert the procvar to an interface method and then free the no > longer required procvardef. Right. The unnecessary work I am currently avoiding. Since I have not yet submitted that part for review, let us avoid premature pointless discussion. > you're parsing something that's in essence a fancy procedure/method > variable which is completely independant of it being implemented by > an interface "Completely independent"? You do realise that method reference types "being <...> interface[s]" is pretty much a part of the specification? ----------8<---------- type M = reference to procedure (const N: Integer); type C = class (TInterfacedObject, M)     procedure Invoke(const N: Integer); virtual; abstract; end; end. ----------8<----------

Yes, it's part of the specification (and I'm not arguing that!), but for the parser itself it is simply an implementation detail. Just like method pointers are implemented using a record that contains both a CodePointer and a data Pointer.

Regards,
Sven

Reply by email

Unknown author
to Sven Barth: Am 07.12.2019 um 22:46 schrieb I had forgotten about pointers to the stack area which I…
Sven Barth wrote
there is no official way to access such parameters

1) At the time of providing that answer on Stack Overflow, Barry Kelly worked as a DCC developer. While it is not truly official, it is pretty close, and satisfies my criterion of "fully conforming to the ABI and particularities of the compiler".
2) That statement of yours is factually incorrect. Again.

there is no stock implementation in Delphi for *any* platform
You remind me of a certain Rudy from the old EMBT forums. It is one thing to not know something due to the lack of experience (with DCC), but to keep insisting despite being repeatedly told otherwise takes an admirable amount of self-confidence :P
----------8<----------
procedure Foo; cdecl; varargs;
var	Z: TVarArgList;
begin
	VarArgStart(Z);
	writeln( VarArgGetValue(Z, Integer) );
	writeln( VarArgGetValue(Z, PChar) );
	VarArgEnd(Z)
end;
begin	{$AppType Console}
	Foo(42, 'You know nothing')
end.
----------8<----------
But only on i386-win32 and x86_64-win64. On Sys V ABI x86_64 targets there is no way around it, because the arguments are passed in registers, not in the stack area.

Two mistakes on your part:
1) Much like SysV x64 ABI, Windows/x64 ABI does use registers for that.
2) Yet the non-stock solution still works, because DCC does support VARARGS (which I keep telling you, but you keep arguing pointlessly), so it spills the registers on the stack.

your patch WILL NOT allow that we DO NOT WANT to support this

1) There is really no need to shout.
2) One reason I intended to allow that with my patch is compatibility with DCC. And I have only brought it up because your understanding of what DCC actually allows appears consistently to be lacking. Should the team reject that aspect of my patch, I am not going to throw a hissy fit and angrily fork into NewNewPascal :)

> And if I use the procvardef parser, I, like Jonas, would need to prohibit "OF OBJECT" and "IS NESTED". The code of procvar_dec as it is currently does not forbid it. So that will need to be improved anyway.

Jonas prohibits them only when type constructor is used in a named type definition. That is one of the bugs I mentioned in the first email.

it's part of the specification (and I'm not arguing that!)

You said, verbatim:

from the user's point of view an anonymous function variable is essentially a procvar as well

The specification dictates that /your/ user should change his mental model from procvar to interface reference :) And since "method reference types are interface types" is not only an implementation detail but now a part of the specification, I feel that parsing them as interfaces makes perfect sense. Anyhow, for the second time I am asking you to stop reviewing code that has not been submitted. I would rather have feedback on https://lists.freepascal.org/pipermail/fpc-devel/2019-December/042264.html , which is kinda blocking me, and we have the subject issue blocking 3.2.

@Jonas: Has the team decided on the amended syntax for C-block references? I am ready to start implementing whichever.

βþ

Reply by email

Jonas Maebe
to Unknown author
Show quoted text 6 lines
> there is no stock implementation in Delphi for *any* platform You remind me of a certain Rudy from the old EMBT forums. It is one thing to not know something due to the lack of experience (with DCC), but to keep insisting despite being repeatedly told otherwise takes an admirable amount of self-confidence :P

There is no need to get personal. Just show how a statement is wrong and be done with it (like with the code fragment you posted), rather than replying to almost every line of every mail how every different way of saying more or less the same thing is wrong.

Sven is the one developer that has spent a lot of time on getting your code and patches ready for integration. And just like the rest of us, he's not perfect.

@Jonas: Has the team decided on the amended syntax for C-block references? I am ready to start implementing whichever.

Sven is already working on it.

Jonas

Reply by email

Unknown author
to Jonas Maebe
Jonas Maebe wrote
replying to almost every line of every mail how every different way of saying more or less the same thing is wrong.

I take issue with that description. Sven was not "saying more or less the same thing" in "different way". Instead, on every next step, without formally admitting the previous mistake, Sven put forward a new claim that yet /another/ aspect does not work. To prove that point, here is the list of VARARGS-related misconceptions (hopefully, also useful for future reference, in case the DCC implementation would again be used to justify FPC design decisions):
- without the built-in va_list, variadic parameters cannot be accessed without BASM:

	+ this can be done entirely in Pascal by taking the address of the preceding parameter; also, there is at least one another solution;

- custom va_list implementations are non-portable hacks (= should not be used):

	+ provided that such an implementation is fully ABI-conformant, it is not a hack;

- VARARGS are not allowed for non-external routine declarations:

	+ on selected platforms, it is allowed; also, it is allowed for nameless routines;

- custom va_list implementation does not work on the platforms where parameters are passed via registers:

	+ the mere presence of VARARGS is enough to instruct DCC to spill those registers, forming a contiguous array on the stack;

- there is no built-in va_list:
+ on selected platforms, compiler intrinsics are available.

Just show how a statement is wrong and be done with it (like with the code fragment you posted)

Not once had Sven ask me to prove any of my statements with a code snippet. And it does not appear that he disbelieved my specific assurances, more like he did not believe my general position "VARARGS works" and kept fruitlessly /guessing/ new circumstances where it does not. (Obviously, the code shown only proves #5 and partially #3 on the above list.)

There is no need to get personal.

I feel like Sven personally derailed this thread by focusing on two aspects not even crucial to the subject. And that feeling is aggravated by my understanding that, had I known that I was presenting the subject issue before the team for the first time, I would not even have mentioned those minor aspects. I would have started with simple "closures are orthogonal to calling conventions" and "this syntax collides with DCC syntax", and, probably, would not have wasted that much time on this thread.

Sven is the one developer that has spent a lot of time on getting your code and patches ready for integration.

Yes. And I have expressed my gratitude on several occasions. However, I am not sure what this fact has to do with this thread. I am reacting solely to what has been written /here/, without prejudice or lenience.

Sven is already working on it.

Speaking of nice conduct: it would have been nice to get informed right away; since, feeling partially responsible for this last-minute blocker, I have already started the work non-specific to the syntax amendment. Anyhow, I believe that concludes my involvement on the subject issue. I thank everyone who immediately recognised a need for the syntax amendment.

βþ

Reply by email

Sven Barth
to Ryan Joseph: Sorry to interject but I'm just curious why this hardline stance was taken. Ryan Joseph

Ryan Joseph via fpc-devel schrieb am So.,
8. Dez. 2019, 23:26:

Show quoted text 12 lines
> On Dec 8, 2019, at 2:30 PM, Sven Barth via fpc-devel < > wrote: > > And no, your patch WILL NOT allow that. We've consciously decided AGAINST implementing varargs functions in Pascal (see https://wiki.freepascal.org/User_Changes_2.6.0#Array_of_const_parameters_and_cdecl_routines ) and we DO NOT WANT to support this. Sorry to interject but I'm just curious why this hardline stance was taken.

First of Object Pascal supports "array of const" which is safer due to a added type field for each entry.

Secondly adding support for implementing varargs functions would mean to add compiler intrinsics to retrieve the parameters for each platform (as not all platforms have a calling convention that allows to use pointer arithmetic like i386 does). Take a look at this blog entry for the x86_64 Sys V ABI: https://blog.nelhage.com/2010/10/amd64-and-va_arg/

We don't want to spend this effort when Object Pascal itself provides a cross platform mechanism.

Please note that *calling* such functions is easier as it follows the usual ABI rules for N parameters.

Regards,
Sven

Reply by email

Marco van de Voort
to Ryan Joseph: Sorry to interject but I'm just curious why this hardline stance was taken. Ryan Joseph

Op 2019-12-08 om 22:08 schreef Ryan Joseph via fpc-devel:

> On Dec 8, 2019, at 2:30 PM, Sven Barth via fpc-devel wrote: > > And no, your patch WILL NOT allow that. We've consciously decided AGAINST implementing varargs functions in Pascal (see https://wiki.freepascal.org/User_Changes_2.6.0#Array_of_const_parameters_and_cdecl_routines ) and we DO NOT WANT to support this. Sorry to interject but I'm just curious why this hardline stance was taken.

Are the valist implementations for gcc,LLVM and msvc the same ?

Reply by email

Ryan Joseph
to Sven Barth: Ryan Joseph via fpc-devel schrieb am So., 8. Dez. 2019, 23:26: First of Object Pascal…
On Dec 10, 2019, at 11:38 AM, Sven Barth via fpc-devel wrote: First of Object Pascal supports "array of const" which is safer due to a added type field for each entry.

From the users standpoint only real difference is the [] syntax and if the array of const is the last (or only) parameter the compiler could infer it right? i.e.

DoThis(firstParam, [1,2,3]);

doesn't really need the [] in this case since the last parameters would have to be an array of const.

Regards,
Ryan Joseph

Reply by email

Sven Barth
to Ryan Joseph

Ryan Joseph via fpc-devel schrieb am Di.,
10. Dez. 2019, 22:29:

Show quoted text 20 lines
> On Dec 10, 2019, at 11:38 AM, Sven Barth via fpc-devel < > wrote: > > First of Object Pascal supports "array of const" which is safer due to a added type field for each entry. > From the users standpoint only real difference is the [] syntax and if the array of const is the last (or only) parameter the compiler could infer it right? i.e. DoThis(firstParam, [1,2,3]); doesn't really need the [] in this case since the last parameters would have to be an array of const. From the view of the *caller* you are mostly right. Though the square

brackets can't be left away, cause we're talking about an array parameter here. If it would be allowed for array of const then it would also need to be allowed for other open array parameters for consistency. But then it wouldn't be consistent with open array arguments in the middle. Each exception makes the language more complex.
Fun fact: There is in fact one such case for open arrays: a single element may be passed without the square brackets.

Also a further difference is that "array of const" does not need to be the last parameter and you can have multiple such parameters in the same call. And it can be used with any calling convention.

Please note that it is possible in FPC to declare an external, variadic function with an "array of const" parameter instead of varargs. The call then looks like a normal "array of const" call in Object Pascal, but internally the arguments are passed using the variadic ABI.

For the *callee* things are vastly different however. With "array of const" you can determine both the amount of arguments as well as the type of each. In variadic functions that either needs to be fix inside the function (e.g. the optional mode parameter of the Posix open() function) or it needs some kind of schematic (the format string in printf/scanf) to determine the argument types.

Regards,
Sven

Reply by email

Ryan Joseph
to Sven Barth
On Dec 10, 2019, at 5:14 PM, Sven Barth via fpc-devel wrote: From the view of the *caller* you are mostly right. Though the square brackets can't be left away, cause we're talking about an array parameter here. If it would be allowed for array of const then it would also need to be allowed for other open array parameters for consistency. But then it wouldn't be consistent with open array arguments in the middle. Each exception makes the language more complex.

Yeah it's an array but it's also slightly annoying when the meaning is basically what we know as "varargs", i.e. an unspecified amount of extra parameters. This common pattern in Format() is a good example of a last parameter array of const which doesn't really gain anything by adding the extra [] every time. I smell another mode switch. :)

Format('%dx%d',[100,100]);

Regards,
Ryan Joseph

Reply by email

Michael Van Canneyt
to Ryan Joseph
Ryan Joseph wrote 10 lines
> On Dec 10, 2019, at 5:14 PM, Sven Barth via fpc-devel wrote: > > From the view of the *caller* you are mostly right. Though the square brackets can't be left away, cause we're talking about an array parameter here. If it would be allowed for array of const then it would also need to be allowed for other open array parameters for consistency. But then it wouldn't be consistent with open array arguments in the middle. Each exception makes the language more complex. > Yeah it's an array but it's also slightly annoying when the meaning is basically what we know as "varargs", i.e. an unspecified amount of extra parameters.

No it is not varargs. See below.

This common pattern in Format() is a good example of a last parameter array of const which doesn't really gain anything by adding the extra [] every time. I smell another mode switch. :)

It does gain something: it tells you it is NOT a varargs, but an array of const, which is a different beast altogether.

"Array of const" is a notation for an open array construct : "array of vararg".

Format('%dx%d',[100,100]);

As Sven already said: It is not varargs, since the array of const has extra info when passed to the function. varargs does not pass any extra info.

So it is good to keep the 2 constructs clearly separated, and the [] makes a a very clear distinction, as it indicates an (open) array, which it in fact is.

This distinction should not be removed. Not even under a modeswitch.

Michael.

Reply by email

Sven Barth
to Unknown author: 1) At the time of providing that answer on Stack Overflow, Barry Kelly worked as a DCC…

Am 09.12.2019 um 01:03 schrieb

Show quoted text 28 lines
On 08.12.2019 22:30, Sven Barth wrote: > there is no official way to access such parameters 1) At the time of providing that answer on Stack Overflow, Barry Kelly worked as a DCC developer. While it is not truly official, it is pretty close, and satisfies my criterion of "fully conforming to the ABI and particularities of the compiler". 2) That statement of yours is factually incorrect. Again. > there is no stock implementation in Delphi for *any* platform You remind me of a certain Rudy from the old EMBT forums. It is one thing to not know something due to the lack of experience (with DCC), but to keep insisting despite being repeatedly told otherwise takes an admirable amount of self-confidence :P ----------8<---------- procedure Foo; cdecl; varargs; var    Z: TVarArgList; begin     VarArgStart(Z);     writeln( VarArgGetValue(Z, Integer) );     writeln( VarArgGetValue(Z, PChar) );     VarArgEnd(Z) end; begin    {$AppType Console}     Foo(42, 'You know nothing') end. ----------8<----------

Well then, let's put this into Delphi 10.2 32-bit then, shall we?

=== output begin ===

[dcc32 Error] tvarargs.dpr(2): E2277 Only external cdecl functions may use varargs
[dcc32 Error] tvarargs.dpr(4): E2003 Undeclared identifier: 'VarArgStart' [dcc32 Error] tvarargs.dpr(5): E2003 Undeclared identifer: 'VarArgGetValue' [dcc32 Error] tvarargs.dpr(5): E2029 '(' expected but ')' found [dcc32 Error] tvarargs.dpr(6): E2029 ',' or ')' expected but identifier 'writeln' found
[dcc32 Error] tvarargs.dpr(6): E2029 '(' expected, but ')' found [dcc32 Error] tvarargs.dpr(7): E2029 ',' or ')' expected but identifier 'VarArgEnd' found

=== output end ===

And would you look at that: Delphi prohibits implementing "varargs" functions as well.

Note: I'm aware that the following code compiles:

=== code begin ===

type
   TTestFunc = reference to procedure(aStr: String) cdecl varargs;
var
   f1: TTestFunc;
begin
   f1 := procedure(aStr: String) cdecl varargs
   begin
   end;
end.

=== code end ===

But I assume this is a bug/oversight, because this compiles as well:

=== code begin ===

type
   TTestFunc = reference to procedure(aStr: String) register varargs;
var
   f1: TTestFunc;
begin
   f1 := procedure(aStr: String) register varargs
   begin
   end;
end.

=== code end ===

Note 2: your code wouldn't work anyway, because your VarArgGetValue() is incorrect. One can not directly pass a type to a non-compiler-magic function, so it either needs to be implemented using PTypeInfo as argument or by using a generic function (which Delphi only supports as members of a structured type, though that could be part of TVarArgList then).

Show quoted text 10 lines
> But only on i386-win32 and x86_64-win64. On Sys V ABI x86_64 targets > there is no way around it, because the arguments are passed in > registers, not in the stack area. Two mistakes on your part: 1) Much like SysV x64 ABI, Windows/x64 ABI does use registers for that. 2) Yet the non-stock solution still works, because DCC does support VARARGS (which I keep telling you, but you keep arguing pointlessly), so it spills the registers on the stack.

I wasn't clear enough again. With the Win64 ABI it works, because it is geared towards that: the caller must allocate the home space for the four registers and puts floating point values also into the integer registers. Then the callee can simply spill all integer registers to the home space and access them using pointers (but even that needs compiler support for varargs then, as the compiler might otherwise decide to spill something else into the home space).

For the Sys V ABI this does not work however, because there is no home space. The compiler detects the presence of the __builtin_vastart intrinsic and then spills all registers (integer and floating point) to the function's local frame. The __builtin_vanext intrinsic then needs to access either the spilled integer or floating point registers in the local frame or those values pass by the stack at a location *above* the return address.

Show quoted text 19 lines
> your patch WILL NOT allow that > we DO NOT WANT to support this 1) There is really no need to shout. 2) One reason I intended to allow that with my patch is compatibility with DCC. And I have only brought it up because your understanding of what DCC actually allows appears consistently to be lacking. Should the team reject that aspect of my patch, I am not going to throw a hissy fit and angrily fork into NewNewPascal :) >> And if I use the procvardef parser, I, like Jonas, would need to >> prohibit "OF OBJECT" and "IS NESTED". > > The code of procvar_dec as it is currently does not forbid it. So > that will need to be improved anyway. Jonas prohibits them only when type constructor is used in a named type definition. That is one of the bugs I mentioned in the first email.

That one took me a while to parse, but you mean that it's only checked in read_named_type, but not if it's using read_anon_type? That would indeed need to be fixed then.

Also it's a further reason to parse the function references using procvar_dec and delay the conversion to an interface cause the directives are handled later outside of read_named_type/read_anon_type (and as we've said for the sake of consistency "reference to procedure; <directive>;" should be allowed).

Show quoted text 16 lines
> it's part of the specification (and I'm not arguing that!) You said, verbatim: > from the user's point of view an anonymous function variable is > essentially a procvar as well The specification dictates that /your/ user should change his mental model from procvar to interface reference :) And since "method reference types are interface types" is not only an implementation detail but now a part of the specification, I feel that parsing them as interfaces makes perfect sense. Anyhow, for the second time I am asking you to stop reviewing code that has not been submitted. I would rather have feedback on https://lists.freepascal.org/pipermail/fpc-devel/2019-December/042264.html , which is kinda blocking me, and we have the subject issue blocking 3.2.

I hope to do this today (Wednesday) or at the latest tomorrow. Didn't have the time before now.

@Jonas: Has the team decided on the amended syntax for C-block references? I am ready to start implementing whichever.

Sorry for not notifying you.

Regards,
Sven

Reply by email

Sven Barth
to Ryan Joseph
Ryan Joseph wrote 6 lines
> On Dec 11, 2019, at 4:16 PM, Michael Van Canneyt wrote: > > It does gain something: it tells you it is NOT a varargs, but an array of > const, which is a different beast altogether. But it's a syntax equivalent for "a variable amount of arguments", i.e. varargs. ;) I guess others don't see it this way however.

Do you consider this as a variable "amount of arguments" as well?

=== code begin ===

function CalcSum(aArg: array of Integer): Integer;
var
   i: Integer;
begin
   Result := 0;
   for i in aArg do
    Result := Result + i;
end;
var
   a: array of Integer;
begin
   Writeln(CalcSum([21, 54, 67, 89]));
   a := [94, 28, 85, 32];
   Writeln(CalcSum(a));
end.

=== code end ===

This uses the same mechanism, namely "open array" as "array of const" is in reality an "array of TVarRec" where the compiler automatically converts the incoming variables into a TVarRec.

In the Pascal world this is considered *one* argument. In contrast Writeln() supports a variable amount of arguments.

Regards,
Sven

Reply by email

Michael Van Canneyt
to Ryan Joseph: But it's a syntax equivalent for "a variable amount of arguments", i.e. varargs. ;) I…
Ryan Joseph wrote 8 lines
> On Dec 11, 2019, at 4:16 PM, Michael Van Canneyt wrote: > > It does gain something: it tells you it is NOT a varargs, but an array of > const, which is a different beast altogether. But it's a syntax equivalent for "a variable amount of arguments", i.e. varargs. ;) I guess others don't see it this way however.

In difference with varargs, Array of const can appear anywhere in the list of arguments: for the compiler, it really is 1 argument.

See e.g. Exception.CreateFmtHelp:

https://docs.freepascal.org/docs-html/current/rtl/sysutils/exception.createfmthelp.html

In private code I use this a lot, I even have

Somecall(fmt : String; args : Array of Const; anOptionalArg : TType = SomeDefault);

for such cases, if you were to drop the [], the compiler has no way to know what to do in general.

Michael.

Reply by email

Martin Frb
to Michael Van Canneyt
Michael Van Canneyt wrote 18 lines
On Wed, 11 Dec 2019, Ryan Joseph via fpc-devel wrote: > > >> On Dec 11, 2019, at 4:16 PM, Michael Van Canneyt >> wrote: >> >> It does gain something: it tells you it is NOT a varargs, but an >> array of >> const, which is a different beast altogether. > > But it's a syntax equivalent for "a variable amount of arguments", > i.e. varargs. ;) I guess others don't see it this way however. Somecall(fmt : String; args : Array of Const; anOptionalArg : TType = SomeDefault);

That still would not break, but it actually is the base for something that would break.

IIRC, the request was not to always drop the [], but only if "array of ..." was the *last* param.

In the above, it is not the last param. But if some code had been written years ago (and published it):
  procedure Somecall(fmt : String; args : Array of Const);

And now it was amended to
  procedure Somecall(fmt : String; args : Array of Const; opt: integer = 0);

Today that would work. Old code without "opt" still compiles.

But if People had used the "drop []" and written code
   SomeCall('x %d', 1,2); // meaning SomeCall('x %d', [1,2]);

That would break.
It was already mentioned, that the [] can be dropped if the array has *exactly one* element.

So with opt in place, and todays ruleset:
   SomeCall('x %d', 1,2); // means SomeCall('x %d', [1],2);

But that means,  if [] are allowed to be dropped at the end, and people had written (*before* "opt" was added)
  SomeCall('x %d', 1,2);  // meaning SomeCall('x %d', [1,2]); then after adding "opt" it would still compile, but it would change meaning. The "2" which would have been part of the array, would suddenly become "opt". (the rule allow dropping [] at the end no longer applies)

Reply by email

Michael Van Canneyt
to Martin Frb
Martin Frb wrote 12 lines
>>> It does gain something: it tells you it is NOT a varargs, but an >>> array of >>> const, which is a different beast altogether. >> >> But it's a syntax equivalent for "a variable amount of arguments", >> i.e. varargs. ;) I guess others don't see it this way however. > > Somecall(fmt : String; args : Array of Const; anOptionalArg : TType = > SomeDefault); That still would not break, but it actually is the base for something that would break.

The point was to demonstrate that array of const is 1 argument. It is not equal to a variable number of arguments.

It was already mentioned, that the [] can be dropped if the array has *exactly one* element.

Not sure what you mean here, but even if there is only 1 argument, today the [] cannot be dropped:

home:~> cat tf.pp
program tf;
uses sysutils;
begin
   writeln(Format('%s','huh?'));
end.
home:~> fpc tf.pp
tf.pp(6,29) Error: Incompatible type for arg no. 2: Got "Constant String", expected "Array Of Const"
tf.pp(8) Fatal: There were 1 errors compiling module, stopping
Fatal: Compilation aborted
Error: /usr/local/bin/ppcx64 returned an error exitcode

Michael.

Reply by email

Martin Frb
to Michael Van Canneyt
Michael Van Canneyt wrote 6 lines
On Thu, 12 Dec 2019, Martin Frb wrote: > That still would not break, but it actually is the base for something > that would break. The point was to demonstrate that array of const is 1 argument. It is not equal to a variable number of arguments.

Yes.
Only if I read the other mails of this argument correctly (and it may be the case I misunderstood something), then that point was never disputed. The call was to "drop the [] if the open array is the last argument in the list"
And this was not, because the called method expects more than one argument. The called message is still declared "array of ...". The called message still accepts it as that single param.

But the "drop []" call was made, because the compiler would be able to determine (even without the []) that the remaining param would be *one* single open-array param.

So my interpretation of this request is, that the clarity of having [], could be dropped for a perceived benefit of maybe less typing or maybe easier-to-read-for-some.

As for my personal view on this: Not in favour.
But anyway I did not want to add my personal view. I thought that potentially the argument was missing the point. If it was not, then apologies for the noise.

Show quoted text 5 lines
> It was already mentioned, that the [] can be dropped if the array has > *exactly one* element. Not sure what you mean here, but even if there is only 1 argument, today the [] cannot be dropped:

I referred to the following previous post in this conversation. (very last line from Sven)

>>>>>>>>
Sven Barth wrote 8 lines
Ryan Joseph via fpc-devel < > schrieb am Di., 10. Dez. 2019, 22:29: DoThis(firstParam, [1,2,3]); doesn't really need the [] in this case since the last parameters would have to be an array of const.

....

Fun fact: There is in fact one such case for open arrays: a single element may be passed without the square brackets.

<<<<<<<<<
I may have misread it. And yes I took it from what I read and did not test it. Having tested it now, it seems that you are right, and brackets are needed too.
I never tried it, because I never needed (nor wanted) it.

Reply by email

Sven Barth
to Michael Van Canneyt: The point was to demonstrate that array of const is 1 argument. It is not equal to a…

Michael Van Canneyt schrieb am Do., 12. Dez. 2019, 15:34:

Show quoted text 21 lines
> It was already mentioned, that the [] can be dropped if the array has > *exactly one* element. Not sure what you mean here, but even if there is only 1 argument, today the [] cannot be dropped: home:~> cat tf.pp program tf; uses sysutils; begin writeln(Format('%s','huh?')); end. home:~> fpc tf.pp tf.pp(6,29) Error: Incompatible type for arg no. 2: Got "Constant String", expected "Array Of Const" tf.pp(8) Fatal: There were 1 errors compiling module, stopping Fatal: Compilation aborted Error: /usr/local/bin/ppcx64 returned an error exitcode

For array of const it is not allowed, but any other open array parameter allows it.

Regards,
Sven

Reply by email

Martin Frb
to Sven Barth
Sven Barth wrote
For array of const it is not allowed, but any other open array parameter allows it.

Ah, interesting.

So then there stands my point from the first mail I wroth in this thread:

IIRC
- the "do not drop []" arguments, where based on design principles.
- the "do drop []" where based on, it will still compile, nothing will break, the same code can and will be generated. It is only a different syntax for the same thing.

Apologies if I misread either side, but the above is what I got....

I brought an example, where actually the "drop [] for last param" would break code.
Therefore it no longer matters if it is or is not against good design. Dropping the [], (in the new case, for last param) will break code that otherwise would be fine.

Reply by email

Michael Van Canneyt
to Sven Barth: Michael Van Canneyt schrieb am Do., 12. Dez. 2019, 15:34: For array of const it is not…
Sven Barth wrote 27 lines
Michael Van Canneyt schrieb am Do., 12. Dez. 2019, 15:34: >> It was already mentioned, that the [] can be dropped if the array has >> *exactly one* element. > > Not sure what you mean here, but even if there is only 1 argument, today > the [] cannot be dropped: > > home:~> cat tf.pp > program tf; > > uses sysutils; > > begin > writeln(Format('%s','huh?')); > end. > home:~> fpc tf.pp > tf.pp(6,29) Error: Incompatible type for arg no. 2: Got "Constant String", > expected "Array Of Const" > tf.pp(8) Fatal: There were 1 errors compiling module, stopping > Fatal: Compilation aborted > Error: /usr/local/bin/ppcx64 returned an error exitcode > For array of const it is not allowed, but any other open array parameter allows it.

Really, are you sure ? Since when is this allowed ?

Today's compiler:

araminta: ~ >fpc -S2 ti.pp
ti.pp(8,6) Error: Incompatible type for arg no. 1: Got "ShortInt", expected "{Open} Array Of LongInt" ti.pp(9,4) Fatal: There were 1 errors compiling module, stopping Fatal: Compilation aborted
Error: /usr/local/bin/ppcx64 returned an error exitcode araminta: ~ >cat ti.pp

procedure a(b : array of integer);
begin
end;
begin
   A(1);
end.

Tested with 3.0.4 and trunk.

And I would not like it if this is allowed.
Imagine
procedure a(b : array of integer);
procedure a(b : integer);
The compiler would have no reason to prefer the second over the first when
it sees a(1);

Such ambiguities should not exist.

Michael.

Reply by email

Michael Van Canneyt
to Michael Van Canneyt
Michael Van Canneyt wrote 54 lines
On Thu, 12 Dec 2019, Sven Barth via fpc-devel wrote: > Michael Van Canneyt schrieb am Do., 12. Dez. 2019, > 15:34: > >>> It was already mentioned, that the [] can be dropped if the array has >>> *exactly one* element. >> >> Not sure what you mean here, but even if there is only 1 argument, today >> the [] cannot be dropped: >> >> home:~> cat tf.pp >> program tf; >> >> uses sysutils; >> >> begin >> writeln(Format('%s','huh?')); >> end. >> home:~> fpc tf.pp >> tf.pp(6,29) Error: Incompatible type for arg no. 2: Got "Constant String", >> expected "Array Of Const" >> tf.pp(8) Fatal: There were 1 errors compiling module, stopping >> Fatal: Compilation aborted >> Error: /usr/local/bin/ppcx64 returned an error exitcode >> > > For array of const it is not allowed, but any other open array parameter > allows it. Really, are you sure ? Since when is this allowed ? Today's compiler: araminta: ~ >fpc -S2 ti.pp ti.pp(8,6) Error: Incompatible type for arg no. 1: Got "ShortInt", expected "{Open} Array Of LongInt" ti.pp(9,4) Fatal: There were 1 errors compiling module, stopping Fatal: Compilation aborted Error: /usr/local/bin/ppcx64 returned an error exitcode araminta: ~ >cat ti.pp procedure a(b : array of integer); begin end; begin A(1); end. Tested with 3.0.4 and trunk.

Delphi prints:
[dcc32 Error] ti.dpr(13): E2192 Constants cannot be used as open array arguments

Michael.

Reply by email

Martin Frb
to Michael Van Canneyt: Really, are you sure ? Since when is this allowed ? Today's compiler: araminta: ~ >fpc…
Michael Van Canneyt wrote 5 lines
On Thu, 12 Dec 2019, Sven Barth via fpc-devel wrote: > For array of const it is not allowed, but any other open array parameter > allows it. Really, are you sure ? Since when is this allowed ?

It works with a variable in the param list, but not with a constant.

program Project1;
procedure Foo(a: array of integer);
begin  end;
var a: integer;
begin
   foo(a);
//  foo(1);  // fails
end.

And then it also works for array of const

program Project1;
procedure Foo(a: array of const);
begin  end;
var a: TVarRec;
begin
   foo(a);
end.

Reply by email

Michael Van Canneyt
to Martin Frb
Martin Frb wrote 30 lines
On 12/12/2019 17:14, Michael Van Canneyt wrote: > On Thu, 12 Dec 2019, Sven Barth via fpc-devel wrote: >> For array of const it is not allowed, but any other open array parameter >> allows it. > > Really, are you sure ? Since when is this allowed ? It works with a variable in the param list, but not with a constant. program Project1; procedure Foo(a: array of integer); begin  end; var a: integer; begin   foo(a); //  foo(1);  // fails end. And then it also works for array of const program Project1; procedure Foo(a: array of const); begin  end; var a: TVarRec; begin   foo(a); end.

Great :(

Hm. I modified the delphi program to check. It also works with a variable...

What kind of braindead "feature" is this ? :(

Michael.

Reply by email

Michael Van Canneyt
to Martin Frb
Martin Frb wrote
On 12/12/2019 17:23, Michael Van Canneyt wrote: > What kind of braindead "feature" is this ? :( Could it be called: Delphi compatibility ?   ;)  :( :(

Probably.

Well, it's not the first time the brains of the Delphi developers took a day off when they implemented something... :(

Michael.

Reply by email

Sven Barth
to Martin Frb: It works with a variable in the param list, but not with a constant. program Project1;…
Martin Frb wrote 9 lines
On 12/12/2019 17:14, Michael Van Canneyt wrote: > On Thu, 12 Dec 2019, Sven Barth via fpc-devel wrote: >> For array of const it is not allowed, but any other open array >> parameter >> allows it. > > Really, are you sure ? Since when is this allowed ? It works with a variable in the param list, but not with a constant.

Yes, I forgot that it requires a variable. ^^'
I had stumbled upon that one some time ago when working on open arrays thus I knew that FPC supports it, but the exact circumstance I could not remember anymore.

Regards,
Sven

Reply by email

Sven Barth
to Michael Van Canneyt: Great :( Hm. I modified the delphi program to check. It also works with a variable...…
Michael Van Canneyt wrote 42 lines
On Thu, 12 Dec 2019, Martin Frb wrote: > On 12/12/2019 17:14, Michael Van Canneyt wrote: >> On Thu, 12 Dec 2019, Sven Barth via fpc-devel wrote: >>> For array of const it is not allowed, but any other open array >>> parameter >>> allows it. >> >> Really, are you sure ? Since when is this allowed ? > > It works with a variable in the param list, but not with a constant. > > program Project1; > procedure Foo(a: array of integer); > begin  end; > > var a: integer; > begin >   foo(a); > //  foo(1);  // fails > end. > > > And then it also works for array of const > > program Project1; > procedure Foo(a: array of const); > begin  end; > > var a: TVarRec; > begin >   foo(a); > end. Great :( Hm. I modified the delphi program to check. It also works with a variable... What kind of braindead "feature" is this ? :(

I don't know why Borland decided to add this back then, but the implementation itself is rather easy as an open array is simply a pointer to the first element and a count. Thus for variables the compiler simply takes the pointer to the variable and passes a constant 1 as count.

Regards,
Sven

Reply by email

Ryan Joseph
to Martin Frb: Ah, interesting. So then there stands my point from the first mail I wroth in this thread:
On Dec 12, 2019, at 11:13 AM, Martin Frb wrote: I brought an example, where actually the "drop [] for last param" would break code. Therefore it no longer matters if it is or is not against good design. Dropping the [], (in the new case, for last param) will break code that otherwise would be fine.

How do C codebases deal with this regarding varargs? I've never done anything large scale or long term in C so I'm not sure what those programmers think of varargs. Maybe they know something I don't.

Regards,
Ryan Joseph

Reply by email

Michael Van Canneyt
to Sven Barth: I don't know why Borland decided to add this back then, but the implementation itself is…
Sven Barth wrote 9 lines
> Hm. I modified the delphi program to check. It also works with a > variable... > > What kind of braindead "feature" is this ? :( I don't know why Borland decided to add this back then, but the implementation itself is rather easy as an open array is simply a pointer to the first element and a count. Thus for variables the compiler simply takes the pointer to the variable and passes a constant 1 as count.

Well I thought about it.

Maybe it stems from string = array of char and open strings. and 'a' is a char or a string = array of char.

Who knows. I am of the opinion it is confusing, but since it is needed for Delphi compatibility there is little we can do.

Michael.

Reply by email

Sven Barth
to Ryan Joseph: How do C codebases deal with this regarding varargs? I've never done anything large scale…
Ryan Joseph wrote 6 lines
> On Dec 12, 2019, at 11:13 AM, Martin Frb wrote: > > I brought an example, where actually the "drop [] for last param" would break code. > Therefore it no longer matters if it is or is not against good design. Dropping the [], (in the new case, for last param) will break code that otherwise would be fine. How do C codebases deal with this regarding varargs? I've never done anything large scale or long term in C so I'm not sure what those programmers think of varargs. Maybe they know something I don't.

They simply don't change such functions? Or grep through the sources and adjust all call sites? The thing is they *know* that adding an additional parameter in front of the variadic arguments is a bad(TM) idea. For Pascal developers they know that one *can* add parameters, because there are the [] after all. It's a different mindset.

Regards,
Sven

Reply by email

Ryan Joseph
to Sven Barth
On Dec 14, 2019, at 12:18 PM, Sven Barth via fpc-devel wrote: In r43684 the syntax was now adjusted, so that an additional "cblock" directive is required (in addition to the calling convention which for macOS can be cdecl or mwpascal).

can you please post an example snippet of this new syntax?

Regards,
Ryan Joseph

Reply by email

Sven Barth
to Sven Barth: Am 09.12.2019 um 01:03 schrieb In r43684 the syntax was now adjusted, so that an…

Sven Barth schrieb am Sa., 14. Dez. 2019,
18:18:

Show quoted text 9 lines
Am 09.12.2019 um 01:03 schrieb > > @Jonas: Has the team decided on the amended syntax for C-block > references? I am ready to start implementing whichever. > In r43684 the syntax was now adjusted, so that an additional "cblock" directive is required (in addition to the calling convention which for macOS can be cdecl or mwpascal).

Hi Blaise,

any update now that we have that adjusted syntax in trunk (and also 3.2) for three months? Maybe other parts that can already be integrated?

Regards,
Sven

Reply by email