* Re: How To Pass Large Object Arguments
2013-11-24 7:20 How To Pass Large Object Arguments FritzVonBraun
2013-11-24 11:12 ` Ludovic Brenta
2013-11-24 12:45 ` Peter C. Chapin
@ 2013-11-25 10:59 ` Georg Bauhaus
2013-11-25 11:09 ` AdaMagica
2013-11-25 16:53 ` adambeneschan
4 siblings, 0 replies; 7+ messages in thread
From: Georg Bauhaus @ 2013-11-25 10:59 UTC (permalink / raw)
On 24.11.13 08:20, FritzVonBraun wrote:
> I am considering passing objects that I think are too big for a copy operation through an access parameter, but that would basically contradict the principle of problem orientation instead of machine orientation. I would really rather be able to handle these situations without having to worry about the underlying mechanism myself.
Exactly. The language rules in LRM 6.2 (see Ludovic's message) make
the compiler choose among the possibilities so established. In addition,
some rules are AS-IF rules, so optimizers can manage parameter passing
as they see fit. They do, drawing upon the compiler writers' knowledge
of the architecture:
If a primitive operation of a "small" tagged type has Inline applied
to it, then, for example, GNAT's optimizer may drop all reference to
the object when translating Object.<primitive operation>.
function Val (Object : OO_Type) return Some_Integer;
pragma Inline (Val);
function Val (Object : in T) return Integer is
begin
return Object.Data;
end Val;
is one example. Its translation, at -gnatn -O2, shows that record
components need not be made publicly visible to address worries
about mechanism.
This feature of the language, i.e. making by-copy/by-reference and in/out
separate concepts, removes the need for access parameters almost everywhere.
And also thinking about them if not problem oriented ;-)
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: How To Pass Large Object Arguments
2013-11-24 7:20 How To Pass Large Object Arguments FritzVonBraun
` (3 preceding siblings ...)
2013-11-25 11:09 ` AdaMagica
@ 2013-11-25 16:53 ` adambeneschan
2013-11-25 17:05 ` sbelmont700
4 siblings, 1 reply; 7+ messages in thread
From: adambeneschan @ 2013-11-25 16:53 UTC (permalink / raw)
On Saturday, November 23, 2013 11:20:53 PM UTC-8, FritzVonBraun wrote:
> Hello all,
>
>
>
> I am fairly new to Ada and I am wondering how I should pass large
> parameters to subprograms like arrays or records that contain other
> components like vectors or lists.
>
> I did a lot of reading but wasnt able to find a definite answer. the
> general consensus I got from Barne's book and various blogs and
> whitepapers from Universities was that in theory IN parameters are
> copied but the compiler manufacturer is free to implement a reference to
> the original object and so on. So basically what I found out there is no
> concrete rule that says "parameter of that size or greater are passed by
> reference internally"
>
> So my question is, is there a de facto standard at least? What does Gnat
> do in such cases? (In all honesty, my programs will never run on
> anything but Gnat, so other compilers don't really matter to me). I am
> considering passing objects that I think are too big for a copy
> operation through an access parameter, but that would basically
> contradict the principle of problem orientation instead of machine
> orientation. I would really rather be able to handle these situations
> without having to worry about the underlying mechanism myself.
The RM has some rules about how certain types are to be passed. Elementary types are always passed by copy; those are types that essentially aren't broken down into subcomponents, i.e. numbers, enumerations, access types. This is true even for IN OUT parameters; the value will be passed by copy, and a new value will be copied back after the procedure or function returns. Tagged types, tasks, protected types, other limited types, and any record or array containing one of those, are always passed by reference. This is true even for IN parameters. If the "vectors" or "lists" you're referring to are types in one of the Ada.Containers packages, then they will be passed by reference since Ada.Containers.Vectors.Vector is defined to be a tagged type, and I think that's true for all the other containers.
But for records and arrays that don't fall into one of those categories, it's up to the compiler. And the compiler's decision may depend on the target processor. One of our compilers (for a particular RISC-ish target) would pass any record up to four 32-bit words by copy, in registers. However, for a Pentium, which has very few registers, an implementation like this wouldn't make sense, and there's no point in copying a record to the stack if it isn't required by the language.
So for record and array types that aren't specified by the RM, you shouldn't worry about the parameter passing mechanism, and let the compiler decide what it thinks the best way is. You should also write code in a way that assumes either one or the other mechanism could be used. That is, if you call Foo(Param => X) where X's type is some record type, and somewhere while Foo is running, something happens that causes a field in X to be modified, Foo itself may or may not notice that that field has changed if it accesses Param.Field. (And that's true even if X is passed by reference, since the compiler could generate code that "knows" Param.Field won't change, since it can't tell whether the actual record will change behind its back.)
-- Adam
^ permalink raw reply [flat|nested] 7+ messages in thread