!standard 5.5 09-03-06 AI05-0140-1/02 !class Amendment 09-02-13 !status No Action (8-0-0) 09-02-22 !status work item 09-02-13 !status received 09-01-19 !priority Medium !difficulty Medium !subject Identity functions !summary (See proposal.) !problem When creating an interface, procedures can be given a default interface that does nothing. However, there is no corresponding capability for functions, which means its always necessary to override a function declared in an interface, even when the function does nothing other than return a parameter. This omission means that designs are pushed into using procedures for routines that would rarely be overridden, even if a function is a more appropriate !proposal Add identity functions with new syntax: function Dereference (Pool : in out Root_Storage_Pool; Access_Value : in Address) return Address is (Access_Value); The parenthesized parameter name must have a type that statically matches the subtype of the function result. !wording ** TBD ** !discussion A way to think of identity functions (and null procedures for that matter) is that they provide a default implementation for an interface. Note that the parameter returned can't be of the interface type (it doesn't have any information to be returnable). That follows from the static matching rule and the rules against functions that return an abstract type. We'd probably want to consider an identity function default for generic formal subprograms as well. An alternative to the plain parenthesized expression would be to add a new keyword to make it crystal-clear that an identity function is being defined. function Dereference (Pool : in out Root_Storage_Pool; Access_Value : in Address) return Address is identity (Access_Value); That seems especially important if we are using this as a default for generic formal subprograms: function Fooey (Value : in Natural) return Natural is (Value); -- Identity function default. function Fooey (Value : in Natural) return Natural is Value; -- A function named Value is the default. Another alternative would be to make this a regular simple return statement: function Dereference (Pool : in out Root_Storage_Pool; Access_Value : in Address) return Address is return Access_Value; allowing an expression of the parameters (thus allowing type conversions and the like). But that seems like it would be opening a can of worms. !examples !ACATS test !appendix From: Randy Brukardt Date: Monday, January 19, 2009 9:20 PM Following is one of a number of "trial-balloon" proposals for future enhancements to Ada. [This is version /01 of the AI - ED.] **************************************************************** From: Niklas Holsti Date: Tuesday, January 20, 2009 2:19 AM A small comment on Randy's syntax for identity functions: > The closest analog to null procedures is identity functions... > > Thus, one could imagine defining a way to define identity functions. > These are unfortunately more complex than null procedures, because of > the need to identify the parameter that is the one returned. So, we've > have to add something like: > > function Dereference (Pool : in out Root_Storage_Pool; > Access_Value : in Address) return Address is > identity (2); > > which means that the function is an identity function on the second > parameter. Rather than giving the parameter number, I would prefer to give the name of the parameter to be returned, and even omit the new "identity" keyword: function Dereference (Pool : in out Root_Storage_Pool; Access_Value : in Address) return Address is Access_Value; This seems both more readable and more robust towards changes in the parameter list. **************************************************************** From: Dmitry A. Kazakov Date: Tuesday, January 20, 2009 2:00 PM > This seems both more readable and more robust towards changes in the > parameter list. I think it would be wrong as well as the Randy proposal, though for different reasons. function Foo (...) return ... is ; in fact provides an implementation for Foo. Presently we have special implementations: 1." is abstract" denotes no implementation 2. "is null" denotes null body 3. "renames " denotes the body of Apart for that renames obviously should be "is ", first two are inconsistent with: 1. Separation of specification and implementation. They shall not be allowed in the package specification. 2. "is null" is inconsistent with the notion of interface. Interface may not have implementations. From this point of view the thing Randy proposes breaks it further. I don't care much about it, because the notion of interface type is rubbish, but introducing rubbish in the first place one should try to uphold it. (:-)) Returning to your proposal, it is wrong because does not look like a body. A body is a literal of some procedural type. From this point of view Randy's identity is a function-valued function, that takes an argument and produces a body. Granted, it should better be Lambda (Access_Value) or better Access_Value'Lambda and Identity (X) should better mean begin return X; end so, for example: type Group is ... function Zero (X : Group) return Element is Identity (0); function One (X : Group) return Element is Identity (1); or type Linked_List_Element is ...; function Next (L : Linked_List_Element) return access Linked_List_Element is Identity (null); Surely once you introduce this stuff you should also allow type conversion: type Linked_List_Element is ...; function Foo (X :String) return Unbounded_String is To_Unbounded_String (X'Lambda); Which is technically a composition: To_Unbounded_String o X'Lambda And also allow it as closures: procedure Inverse (A : in out Vector) is begin Update (A, -X'Lambda); end Inverse; Instead of procedure Inverse (A : in out Vector) is function Update_Element (X :Element) return Element is begin return -X; end Update_Element; begin Update (A, Update_Element'Access); end Inverse; I hope it is clear where it goes... ****************************************************************