Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

calling function but ignoring results

251 views
Skip to first unread message

Matt Borchers

unread,
Jun 29, 2021, 3:25:27 PM6/29/21
to
It is not very often that ignoring a function result is okay, but I have run across many instances of the following block structure in code over the years:

declare
dont_care : BOOLEAN;
begin
dont_care := foo( x, y );
end;

I also see the procedure wrapper used in some cases -- usually when exported in a package specification:

procedure FOO( x, y ) is
b : BOOLEAN;
begin
b := foo( x, y );
end FOO;

The procedure adds nothing to the code except another thing to maintain when the function interface needs modification.

Is there a Ada 202x feature to support calling functions and ignoring the result? If not, I'm wondering if the @ symbol recently introduced for assignments could be used? How would people feel about the following?

@ := foo( x, y );

This would discard the result of the function. This could obviously lead to memory leaks (without reference counting), but the syntax could be restricted for use on functions that do not return uncontrolled access types or these functions could be marked with a keyword to make it legal for it to be called in such a way when the programmer knows that the access returned should not be "freed" by the caller (such as a pointer into an existing structure).

I have not given this much thought so I'm sure there are reasons why this can't (or shouldn't) be done in general. Regardless, there are probably many that would agree with me that the declare block and the wrapper procedure options are annoying and could be considered superfluous for lack of a better way to write the code more simply.

Matt

Jeffrey R. Carter

unread,
Jun 29, 2021, 3:52:40 PM6/29/21
to
On 6/29/21 9:25 PM, Matt Borchers wrote:
> It is not very often that ignoring a function result is okay, but I have run across many instances of the following block structure in code over the years:
>
> declare
> dont_care : BOOLEAN;
> begin
> dont_care := foo( x, y );
> end;

This sort of thing usually indicates a design problem.

> Is there a Ada 202x feature to support calling functions and ignoring the result?
If you want to use a language that allows this, then you probably shouldn't be
developing S/W.

--
Jeff Carter
"Blessed is just about anyone with a vested interest in the status quo."
Monty Python's Life of Brian
73

Dmitry A. Kazakov

unread,
Jun 29, 2021, 4:34:45 PM6/29/21
to
On 2021-06-29 21:52, Jeffrey R. Carter wrote:
> On 6/29/21 9:25 PM, Matt Borchers wrote:
>> It is not very often that ignoring a function result is okay, but I
>> have run across many instances of the following block structure in
>> code over the years:
>>
>> declare
>>      dont_care : BOOLEAN;
>> begin
>>      dont_care := foo( x, y );
>> end;
>
> This sort of thing usually indicates a design problem.

True. But there are exceptions from the rule:

1. Bindings to other languages. You normally have the result and you
quite often ignore it because it is useless.

2. Side effects of the call. Normally you would overload a function with
a procedure, like here:

function Pop (Stack : not null access Stack_Type) return Element;
procedure Pop (Stack : in out Stack_Type);

But you will have a problem (which BTW the proposal fail to address)
when overloading is solely on the result:

function Get (File : File_Type) return Integer;
function Get (File : File_Type) return Float;
function Get (File : File_Type) return String;

Now if you wanted to skip an integer in the file you could not do it in
the proposed way:

@ := Get (Standard_Input); -- Ambiguous

@ := Integer'(Get (Standard_Input)); -- Ugly

And of course, as many times proposed before a better syntax would be
the null statement:

null <expression>; -- Does not address the problem either

>> Is there a Ada 202x feature to support calling functions and ignoring
>> the result?
> If you want to use a language that allows this, then you probably
> shouldn't be developing S/W.

I would not say that pieces like:

declare
Ignore : constant Bar := Foo (Baz);
begin
null;
end;

or

if Foo (X) then null; end if;

are good engineering. But excessive overloading may lead to unexpected
collisions if you have many parameters with defaults.

--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

Randy Brukardt

unread,
Jun 30, 2021, 2:06:41 AM6/30/21
to
"Dmitry A. Kazakov" <mai...@dmitry-kazakov.de> wrote in message
news:sbg04v$i7i$1...@gioia.aioe.org...
...
> Now if you wanted to skip an integer in the file you could not do it in
> the proposed way:
>
> @ := Get (Standard_Input); -- Ambiguous
>
> @ := Integer'(Get (Standard_Input)); -- Ugly

Maybe you think qualification is "ugly", but it is precisely the Ada tool
for this sort of problem. It wouldn't make sense to invent a new mechanism
when an existing one does the job just fine (and it's hard to imagine a
disambiguation mechanism that didn't include the subtype name).

> I would not say that pieces like:
>
> declare
> Ignore : constant Bar := Foo (Baz);
> begin
> null;
> end;

In Ada 202x, renaming is easier (assuming the usual case where overloading
isn't involved):

declare
Ignore renames Foo (Baz);
begin
null;
end;

BTW, I disagree with the OP's premise. To me, this sort of thing is
*exactly* what you need to do, since it makes it clear that you are ignoring
the result. And that typically is hidden inside of a thicker binding, so
it's pretty rare (it won't happen in well-designed Ada packages, but as
Dmitry says, it will often happen in interfacing, at least with the
Microsoft stuff!).

...

> But excessive overloading may lead to unexpected collisions if you have
> many parameters with defaults.

Excessive overloading is obviously bad, so the above doesn't say much. :-)
Determining when overloading is excessive is the hard part. Recent
experience suggests that a lot of overloading is ultimately execessive (the
need to change the name of some containers procedures demonstrates this!!)

Randy.


Luke A. Guest

unread,
Jun 30, 2021, 6:18:27 AM6/30/21
to
On 29/06/2021 20:52, Jeffrey R. Carter wrote:

>> declare
>>      dont_care : BOOLEAN;
>> begin
>>      dont_care := foo( x, y );
>> end;
>
> This sort of thing usually indicates a design problem.

Or interfacing with C.

>
>> Is there a Ada 202x feature to support calling functions and ignoring
>> the result?
> If you want to use a language that allows this, then you probably
> shouldn't be developing S/W.
>

That's literally every C programmer then.

Luke A. Guest

unread,
Jun 30, 2021, 6:27:00 AM6/30/21
to

On 29/06/2021 20:25, Matt Borchers wrote:
> It is not very often that ignoring a function result is okay, but I have run across many instances of the following block structure in code over the years:
>
> declare
> dont_care : BOOLEAN;
> begin
> dont_care := foo( x, y );
> end;

declare
Dont_Care : constant Boolean := foo (x, y); -- Uppercase is so pascal!
pragma Unused (Dont_Care); -- GNAT specific
begin
null;
end;

I would put into a procedure, especially if it's a binding to C.

Simon Wright

unread,
Jun 30, 2021, 3:31:08 PM6/30/21
to
"Luke A. Guest" <lag...@archeia.com> writes:

> declare
> Dont_Care : constant Boolean := foo (x, y); -- Uppercase is so pascal!
> pragma Unused (Dont_Care); -- GNAT specific
> begin
> null;
> end;

There are several names that you don't need pragma Unreferenced (not
Unused) for - see
https://docs.adacore.com/live/wave/gnat_rm/html/gnat_rm/gnat_rm/implementation_defined_pragmas.html#pragma-unreferenced

"For the variable case, warnings are never given for unreferenced
variables whose name contains one of the substrings DISCARD, DUMMY,
IGNORE, JUNK, UNUSED in any casing. Such names are typically to be
used in cases where such warnings are expected. Thus it is never
necessary to use pragma Unreferenced for such variables, though it is
harmless to do so."

Rod Kay

unread,
Jun 30, 2021, 7:06:27 PM6/30/21
to
On 30/6/21 8:26 pm, Luke A. Guest wrote:
>
> declare
>    Dont_Care : constant Boolean := foo (x, y); -- Uppercase is so pascal!
>    pragma Unused (Dont_Care); -- GNAT specific
> begin
>    null;
> end;
>

or even ...

declare
Dont_Care : constant Boolean := Foo (X, Y) with Unreferenced;
begin
null;
end;

Stephen Leake

unread,
Jun 30, 2021, 8:06:34 PM6/30/21
to
Matt Borchers <mattbo...@gmail.com> writes:

> It is not very often that ignoring a function result is okay, but I
> have run across many instances of the following block structure in
> code over the years:
>
> declare
> dont_care : BOOLEAN;
> begin
> dont_care := foo( x, y );
> end;

With, GNAT, this can be:

declare
dont_care : BOOLEAN := foo( x, y );
pragma Unreferenced (dont_care);
begin
null;
end;

which makes the intent clear. I don't know if Unreferenced was proposed
as a language addition; it's not in Ada 202x.

--
-- Stephe

Randy Brukardt

unread,
Jun 30, 2021, 11:55:15 PM6/30/21
to
"Stephen Leake" <stephe...@stephe-leake.org> wrote in message
news:867diay...@stephe-leake.org...
...
> declare
> dont_care : BOOLEAN := foo( x, y );
> pragma Unreferenced (dont_care);
> begin
> null;
> end;
>
> which makes the intent clear. I don't know if Unreferenced was proposed
> as a language addition; it's not in Ada 202x.

Unreferenced controls warnings, which (with one exception) are not an Ada
concept. So how would we describe what it does? Aspect unreferenced does
nothing at all?? :-)

One could imagine an aspect that caused a Legality Rule against an actual
reference, but I don't think that is what the GNAT aspect does.

Randy.


Gabriele Galeotti

unread,
Jul 1, 2021, 2:07:43 PM7/1/21
to
Yes, you are right.
But sometimes it is necessary (especially at the H/W level) to force a read of
a peripheral register in order to obtain a specific behaviour, e.g., clear an interrupt
or latch a value previously written; in these cases what you read is useless.
G

Marius Amado-Alves

unread,
Jul 2, 2021, 3:32:24 AM7/2/21
to
On Thursday, 1 July 2021 at 19:07:43 UTC+1, Gabriele Galeotti wrote:
> But sometimes it is necessary...

Yes, but the frequency is too low to justify yet another feature of the language, IMO.

Nasser M. Abbasi

unread,
Jul 2, 2021, 9:22:58 PM7/2/21
to
On 6/29/2021 2:25 PM, Matt Borchers wrote:
> It is not very often that ignoring a function result is okay, but I have run across many instances of the following block structure in code over the years:
>
> declare
> dont_care : BOOLEAN;
> begin
> dont_care := foo( x, y );
> end;
>
> I also see the procedure wrapper used in some cases -- usually when exported in a package specification:
>
> procedure FOO( x, y ) is
> b : BOOLEAN;
> begin
> b := foo( x, y );
> end FOO;
>

fyi, Matlab had this for years:

https://www.mathworks.com/help/matlab/matlab_prog/ignore-function-outputs.html

"
This example shows how to ignore specific outputs from a function using the tilde (~) operator.
To ignore function outputs in any position in the argument list, use the tilde operator. For example, ignore the first output using a tilde.

[~,name,ext] = fileparts(helpFile);

"

--Nasser

Matt Borchers

unread,
Jul 3, 2021, 12:59:19 AM7/3/21
to
Thanks for the feedback. I guess I have to live with five lines to accomplish what one should do regardless of the numerous variety of ways to accomplish this. I mostly appreciate the wordiness of Ada for the clarity it offers to the code maintainers, but in some cases the extra wordiness offers nothing.

Related to this, I really appreciate the new parenthesized expressions as it offers a clean way to declare simple functions. GNAT 21.2 was just released today and includes declare expressions. I don't have the compiler yet, but I wonder if this would work:

procedure FOO( x, y ) is (declare b : BOOLEAN := foo( x, y ));

but it seems likely that an expression returns a value and would not be allowed in this instance.

Gautier write-only address

unread,
Jul 3, 2021, 3:37:09 AM7/3/21
to
Le samedi 3 juillet 2021 à 06:59:19 UTC+2, Matt Borchers a écrit :
> Thanks for the feedback. I guess I have to live with five lines to accomplish what one should do regardless of the numerous variety of ways to accomplish this. I mostly appreciate the wordiness of Ada for the clarity it offers to the code maintainers, but in some cases the extra wordiness offers nothing.

If you use functions properly (only "in" parameters and not side effects) you don't have this issue at all.
Interfacing with C is an edge case which doesn't need to add more noise in the Ada syntax, IMHO.

Gautier write-only address

unread,
Jul 3, 2021, 3:42:38 AM7/3/21
to
*no* side effects

Gautier write-only address

unread,
Jul 3, 2021, 3:46:04 AM7/3/21
to
> [~,name,ext] = fileparts(helpFile);

In Ada it would be:
Info := File_Parts (Help_File);

You would use Info.name and Info.ext informations in the record only and ignore the other field.
Not much more complicated...

Niklas Holsti

unread,
Jul 3, 2021, 3:57:23 AM7/3/21
to
On 2021-07-03 10:37, Gautier write-only address wrote:
> Le samedi 3 juillet 2021 à 06:59:19 UTC+2, Matt Borchers a écrit :
>> Thanks for the feedback. I guess I have to live with five lines to
>> accomplish what one should do regardless of the numerous variety of
>> ways to accomplish this. I mostly appreciate the wordiness of Ada
>> for the clarity it offers to the code maintainers, but in some
>> cases the extra wordiness offers nothing.
>
> If you use functions properly (only "in" parameters and not side
> effects) you don't have this issue at all.


However, the problem then changes to ignoring unneeded "out" parameters
of procedures, and the only way (currently) is to declare dummy output
variables and then leave them unused.

But it is not a big problem, and not worth changing the language, IMO.


> Interfacing with C is an edge case which doesn't need to add more
> noise in the Ada syntax, IMHO.

I agree.

Stephen Leake

unread,
Jul 3, 2021, 6:42:47 AM7/3/21
to
"Randy Brukardt" <ra...@rrsoftware.com> writes:

> "Stephen Leake" <stephe...@stephe-leake.org> wrote in message
> news:867diay...@stephe-leake.org...
> ...
>> declare
>> dont_care : BOOLEAN := foo( x, y );
>> pragma Unreferenced (dont_care);
>> begin
>> null;
>> end;
>>
>> which makes the intent clear. I don't know if Unreferenced was proposed
>> as a language addition; it's not in Ada 202x.
>
> Unreferenced controls warnings, which (with one exception) are not an Ada
> concept.

This could be another exception, or we could make it an Ada concept.

> So how would we describe what it does? Aspect unreferenced does
> nothing at all?? :-)
>
> One could imagine an aspect that caused a Legality Rule against an actual
> reference, but I don't think that is what the GNAT aspect does.

It does give you a warning if the variable is referenced.

--
-- Stephe

Gabriele Galeotti

unread,
Jul 3, 2021, 7:35:06 AM7/3/21
to
Well, I agree it's ok to keep a rigid language semantics. The price to pay is then
accept some kind of warning (that add noise), or write the offending code
in an ad-hoc machine language fragment (which add further noise).
To be honest, I see this kind of feature as a "normal" pragma to the underlying
optimizer/linker/etc. Unfortunately, the H/W world is often far from perfect.

Gabriele Galeotti

unread,
Jul 3, 2021, 7:46:07 AM7/3/21
to
On Friday, July 2, 2021 at 9:32:24 AM UTC+2, amado...@gmail.com wrote:
Note: in the last reply, I am referring to the use of pragma Unreferenced, not a new language feature.

G

Simon Wright

unread,
Jul 3, 2021, 3:11:09 PM7/3/21
to
or aspect Unreferenced, or if you're prepared to accept GNAT extensions
anyway, just call the not-referenced variable Dummy, or Unused, or .. I
listed the relevant variable names upthread.

I suspect you _won't_ get a warning if you do reference a variable named
Dummy, but at that point it should be pretty obvious that something's
wrong.

I think any compiler needs some facility like this, at least if it has
any pretensions to interfacing to foreign languages; but it probably
won't be the same as Ada's.

Simon Wright

unread,
Jul 4, 2021, 3:22:29 AM7/4/21
to
Simon Wright <si...@pushface.org> writes:

> I think any compiler needs some facility like this, at least if it has
> any pretensions to interfacing to foreign languages; but it probably
> won't be the same as Ada's.

... the same as *GNAT*'s.

Sorry, people

Randy Brukardt

unread,
Jul 6, 2021, 7:07:42 PM7/6/21
to
"Simon Wright" <si...@pushface.org> wrote in message
news:lya6n32...@pushface.org...
...
> I think any compiler needs some facility like this, at least if it has
> any pretensions to interfacing to foreign languages; but it probably
> won't be the same as Ada's.

Perhaps "any compiler that tries to warn about unused objects". Janus/Ada
doesn't do that, so it doesn't need some facility to turn it off, either.
But I grant that if it did have such a warning, then some method to turn it
off is needed. (We have a pragma Warning_Level for turning off classes of
warnings in selective areas, nothing for individual warnings -- my
assumption has been that a warning message mught change when the compiler
gets upgraded, but the class of warning will not [unless of course there is
something else wrong].)

Randy.


G.B.

unread,
Jul 9, 2021, 2:14:10 PM7/9/21
to
On 30.06.21 08:06, Randy Brukardt wrote:

> In Ada 202x, renaming is easier (assuming the usual case where overloading
> isn't involved):
>
> declare
> Ignore renames Foo (Baz);
> begin
> null;
> end;

Is this "type-less" naming a copy of the popular omission schemes
like auto in C++? Optional type annotations in Swift, or Scala?
Too many of those omissions have invited, uhm, a number of things.

They'll be good, for sure, when securing the workplace semantically;
also good for implementors of more complex type inference algorithms
and, consequently, for makers of the CPUs that are needed to properly
handle the omissions. I think the proper number of omissions is
a subject of research at ETH Zürich. They are trying to find
a sweet spot that makes inference finish in reasonable time.

Niklas Holsti

unread,
Jul 9, 2021, 3:20:59 PM7/9/21
to
On 2021-07-09 21:14, G.B. wrote:
> On 30.06.21 08:06, Randy Brukardt wrote:
>
>> In Ada 202x, renaming is easier (assuming the usual case where
>> overloading
>> isn't involved):
>>
>>     declare
>>        Ignore renames Foo (Baz);
>>     begin
>>        null;
>>     end;
>
> Is this "type-less" naming a copy of the popular omission schemes
> like auto in C++? Optional type annotations in Swift, or Scala?


I don't know all the origins of this language change, but it can be seen
as a correction because it avoids the wart in the earlier Ada form of
renaming, where a (sub)type name is included. The wart is that the
constraints of that (sub)type are essentially ignored, and so can be
misleading.

AI12-0275 seems to be the main origin of this change:

http://www.ada-auth.org/cgi-bin/cvsweb.cgi/ai12s/ai12-0275-1.txt?rev=1.9&raw=N

Randy Brukardt

unread,
Jul 9, 2021, 10:57:30 PM7/9/21
to
"Niklas Holsti" <niklas...@tidorum.invalid> wrote in message
news:ikrlsp...@mid.individual.net...
...
>> Is this "type-less" naming a copy of the popular omission schemes
>> like auto in C++? Optional type annotations in Swift, or Scala?
>
>
> I don't know all the origins of this language change, but it can be seen
> as a correction because it avoids the wart in the earlier Ada form of
> renaming, where a (sub)type name is included. The wart is that the
> constraints of that (sub)type are essentially ignored, and so can be
> misleading.

Right; the name of the type is often a lie vis-a-vis the subtype properties;
moreover, it is often the case that the type is included in the renamed
item:

Foo : renames Some_Type'(Bar(Obj));

Repeating the type in such cases is not useful and violates DRY ("Do Not
Repeat Yourself"):

Foo : Some_Type renames Some_Type'(Bar(Obj));

We felt this was something that was better handled by style guides rather
than imposing unnecessarily wordy syntax.

> AI12-0275 seems to be the main origin of this change:
>
> http://www.ada-auth.org/cgi-bin/cvsweb.cgi/ai12s/ai12-0275-1.txt?rev=1.9&raw=N

The actual motivation behind this change was a strong desire for a shorter
way to write bindings in declare expressions. We tried a number of things,
but they all seemed oddly special case. Eventually, we settled on using
normal syntax throughout declare expressions, but simplified the syntax for
renaming in all cases. The tipping point was noticing the duplication in
examples like the above, along with the fact that the subtype given is
ignored anyway.

If we were designing Ada from scratch, the subtype in a renames would have
to statically match the nominal subtype of the name being renamed. But that
wasn't required in Ada 83 and it would be way too incompatible to require
now. (The reason that Ada 83 didn't require it? Jean Ichbiah didn't want to
have to define "static matching" -- according to an old thread that John
Goodenough dug up. Of course the Ada 9x team decided such a concept was
necessary and added it to the language, so we ended up with most constructs
using static matching, but renames being different.)

Randy.


Shark8

unread,
Jul 12, 2021, 11:56:56 AM7/12/21
to
On Friday, July 9, 2021 at 12:14:10 PM UTC-6, G.B. wrote:
> They'll be good, for sure, when securing the workplace semantically;
> also good for implementors of more complex type inference algorithms
> and, consequently, for makers of the CPUs that are needed to properly
> handle the omissions. I think the proper number of omissions is
> a subject of research at ETH Zürich. They are trying to find
> a sweet spot that makes inference finish in reasonable time.
I tend to dislike type-inference* almost altogether; I think Ada 2012 and before got it right: very constrained and deterministic contexts (eg the for loop's index).
Yes, I realize there's systems like Haskell that are good about types, but as you say these have inferences that take a while. While I'm all in favor of making the compiler do the tedious work, given that types are [in general] a static portion of the program as a whole it should be possible (to borrow from the GPS UI) to throw up the little wrench/auto-fix option and "fill in" the types found so that the next compile doesn't have to infer types... but I suspect that most implementations will instead simply do the inference again and again and again on each compile and waste your time.

* It invites the "could possibly work" C-ish mentality, rather than the "cannot possibly not-work" Ada-mentality, IMO.
0 new messages