LCS Number: | LCS-2016-072 |
Version: | 13 |
Date: | 21-Oct-2016 (Ver 1), 21-Nov-2016 (Ver 2), 21-Dec-2016 (Ver 3), 2016-Dec-30 (Ver 4), 2017-Jan-4 (Ver 5) 2017-Jan-16 (Ver 6), 2017-Feb-8 (Ver 7), 2017-Feb-14 (Ver 8), 2017-Feb-15 (Ver 9), 2017-Feb-24 (Ver 10), 2017-Mar-14 (Ver 11), 2017-Mar-15 (Ver 12), 2017-Mar-16 (Ver 13) |
Status: | |
Author: | Kevin Jennings |
Email: | KevinJennings |
Source Doc: | FunctionKnowsVectorSize |
Summary: | Allow for functions to have access to attributes of the target of a function. |
function TO_SIGNED(X : INTEGER, SIZE : NATURAL) return SIGNED; function TO_SIGNED(X : INTEGER) return myreturnthing : SIGNED; ... function TO_SIGNED(X : INTEGER) return myreturnthing : SIGNED is begin return TO_SIGNED(X, myreturnthing'length); end function TO_SIGNED;Now, I think that if you had two functions undifferentiated but for a known target, that would be an error, the same as it currently would be to have to undifferentiated functions. But that shouldn't require an explicit statement in the LRM, that's just keeping existing behavior.
-- ERROR: conflicts with TO_SIGNED(X : INTEGER, SIZE : NATURAL) return SIGNED; function TO_SIGNED(X: INTEGER, OFFSET: INTEGER) return differenttarget: SIGNED;-- Rob Gaddi - 2016-12-14 This would be a very convenient feature to have! But I must vote against it in its current form. Rationale for "NO" vote:
Most programming languages are designed to be context-free grammars (CFGs), and this is generally considered a good thing. If I remember correctly from the last round of changes, VHDL is not currently in the CFG class. Still, it signals to me that this is likely to require significantly more work in the parser.
Suggestion for improvement:
The following is a minor annoyance. The source proposal references "another (as yet unwritten) proposal" for adding scalar attributes. It's a stretch to call this "part of the proposal" and push it into the LCS. I did read this LCS during the two years that it was up, and I would have commented had it been part of the proposal, not just a notional reference to a to-be-written proposal. (You used stronger language in making a very similar argument in an email you sent 30 Apr 2014.
-- Ryan Hinton - 2016-12-15
Rob, I agree with you. So why do we need to have the target in the signature ? That's useless!
-- Tristan Gingold - 2016-12-15
Kevin, can we declare this function: function to_signed (a : integer) return a : signed; I think nothing in this proposal makes this declaration invalid. The problem is that target is not described.
-- Tristan Gingold - 2016-12-15
@Patrick: Your statement is true but I miss the relation to any of my comments. I would just rely on a function having a name and returning a value.
-- Thomas Preusser - 2016-12-15
This proposal seems to be incomplete, and it has several issues.
-- Ernst Christen - 2016-12-15
Version 3 (still a draft at this time) changes:
- @Several: Not sure what to do with Page 28 and 'Signatures'. The idea that I'm trying to get across is that there are known situations where this type of function cannot be used because the output of the function feeds into an expression. A simple example would be "My_uns := to_unsigned(1) + to_unsigned(2);". What needs to change in the LRM to define this limitation? Eliminated 'Signatures', I thought it belonged, but apparently not.
- @Tristan: "function to_signed (a : integer) return a : signed; I think nothing in this proposal makes this declaration invalid. The problem is that target is not described". There could be a couple of different resolutions here, which one makes most sense? 1. Declare a warning or error if 'target' is not distinct from each of the parameters? 2. 'Target a' hides 'parameter a'. 3. Something else?
- @Ryan #1 "To be consistent, this feature should be available in an initial value for a constant, signal, or variable as well as for assignment" KJ: In what way is what I've written make this not available to use for an initial value for a constant, signal, or variable?
- @Ryan #2 "same _parameter and result type profile_", still figuring out what this means, list-o-things-to-do
- @Ryan #3: "I think you want an identifier for your return formal instead of a target. You're probably right, list-o-things-to-do. KJ: Changed to identifier, 2016-12-20.
- @Ryan #4: "Nowhere in the proposal does it mention changing the LRM so attribute references retrieve the value from the actual". KJ: Added change to section 4.2.2.2 Constant and variable parameters
- @Ryan #5: "Attributes of an object are accessible via the subtype attribute". Getting the attributes of the subtype is not what is desired here. The proposal is trying to get at the attributes of the actual so if you have "signal x: integer range 5 to 10;", and x is passed into a function MyFunc (y:integer) as MyFunc (y
> x), the proposal is trying to retrieve y'left as 5, y'right as 10. It is not trying to get the left and right attributes of the subtype integer.
- @Ryan #6: "...change to page 28 makes a signature matching dependent on how it's used". KJ: Changes to 'Signatures' removed.
- @Ernst #1: bold format on [target :] KJ: Removed, the bold was unintentional.
- @Ernst #2: "target is intended to be the name of a production, this production is missing", list-o-things-to-do. KJ: Changed to identifier, 2016-12-20.
- @Ernst #3: "become visible in the subprogram body? There are currently no changes to clause 12", list-o-things-to-do KJ: Added on page 186, 2016-12-20.
- @Ernst #4: "A comma should be added" Should be added after "(if any)" in the text "retrieve attributes of the target (if any) the subtype of" or someplace else? KJ: Added a comma 2016-12-20
- @Ernst #5: "The new paragraph on p.20 has the form of a note, not a definition", KJ: Not sure what are you referring to. If you meant page 21 instead, then the 'non-note' portion is addressed with changes to section 4.2.2.2 Constant and variable parameters
- @Ernst #6: "The changes of p.21 are in the notes. These have no semantic meaning...", KJ: Added change to section 4.2.2.2 Constant and variable parameters
- @Ernst #7: "If we are after the attributes of the actual, what if the actual is of type universal_integer or universal_real". If a literal such as the number 3 is passed in (which is the only way one could get universal_integer, right?), then the proposal would expect attributes of the 'actual', to be generated. So for function MyFunc (y:integer) as MyFunc (y => 3), the proposal would expect y'left = y'right = y'low = y'right = 3. Unless my changes to 4.2.2.2 do the trick, I'm not sure how/where to specify that behavior but that would be the intent of the proposal.
- @Ernst #8, 9: "comment on the need for the target in the signature", KJ: Changes to 'Signatures' have been removed.
- @Ernst #10: "The symbolic prefix A for predefined attributes of scalars is misleading". Changed to 'S' for scalar.
- @Ernst #11: "It seems that this proposal allows functions to be defined that have restrictions where they can be called. This is highly undesirable.". KJ: It is also undesirable to have to provide parameters to a function to tell the function something that the user can clearly see (i.e. y <
to_unsigned(3, y'length), and many use cases when using the fixed point package where one has to pass in ranges). The current practice can lead to latent design errors in addition to making the code less readable. Nobody has come up with a better way to accomplish the goal of the proposal yet which is to remove something that really shouldn't be needed. @ Ernst #11 sub-bullets "What happens if a function that reads attributes of its (symbolic) target is called as a term in an expression" KJ: Refer to changes to section 4.2.2.2
- @Ernst #12: "Should there be restrictions for resolution functions?" KJ: I don't know, is there a reason that they should?
- @Ernst #13: "what if the instantiation occurs with a record type?" KJ: I'm not sure I follow what you're getting at with this bullet and this question in particular. Scalar attributes would return the bounds of the scalar range (this is the new thing), array attributes would return the index range as they do today. Also available to the user today is the ability to get at the attributes of the subtype of a parameter. In all of these instances, these attributes are useful to the user. What exactly is your concern here?
-- Kevin Jennings - 2016-12-16
It appears that much of the red font marking changes has been lost. KJ: Fixed 2016-12-20, but no idea whether it will stick this time or not.
- Reply to @Tristan: Can you point to the text that makes this invalid within existing interface lists?
procedure foo(a:integer, a:integer);
- Reply to @Ryan #3, applicable to several other comments by several authors (e.g. @Ernst #2): The target production is listed in Annex C (syntax summary) and references 10.5.2.1. So the grammar symbol is valid, but it allows for an aggregate, which seems wrong to me. That's why I suggested replacing the target symbol with the identifier symbol as in the other interface_list productions.
- Reply to @Ryan #4: LRM 4.2.2.2 (page 21) discusses that parameters of class constant and variable can be passed by value in many cases. This tells me that the formal identifier in a subprogram declaration is its own object, not just an alias to the actual. So when you ask for x'subtype'left inside a subprogram, you get the attribute from the formal x, not from the actual associated with x. So changing 4.2.2.2 should be included in your list-o-things-to-do. See also the reflector discussion last week with subject "Subprogram attribute values come from formal".
- Reply to @Ryan #5: LRM 6.3 states, "A subtype indication defines a subtype of the base type of the type mark." (Emphasis mine.) If you take a look at the signal declaration rule, signal x: integer range 5 to 10;, the integer range 5 to 10 is a subtype indication, and defines a subtype of integer. When the tool evaluates x'subtype'left, it will give 5, not integer'left. (I confirmed this in a tool that typically implements the standard correctly.) The mechanism is the same when x is declared as a constrained sfixed object: the constraints in its declaration infer a new subtype specifically for x (unless no constraints are applied).
- Reply to @Ernst #7: We can't use type universal_integer on an interface list, so the actual coming in will already have an implicit conversion to integer. Right?
-- Ryan Hinton - 2016-12-19
Reply to @Ryan #5: LRM 6.3 states, "A subtype indication defines a subtype of the base type of the type mark." (Emphasis mine.) If you take a look at the signal declaration rule, signal x: integer range 5 to 10;, the integer range 5 to 10 is a subtype indication, and defines a subtype of integer. When the tool evaluates x'subtype'left, it will give 5, not integer'left. (I confirmed this in a tool that typically implements the standard correctly.)
KJ reply: But this is not the case within a subprogram. In a subprogram, x'subtype'left returns the 'left attribute of the formal type integer (-2147483648), not the 'left attribute of the constrained actual (5). Below is sample code and output, using tool M, do you want to check it your tool?
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity foo is end foo; architecture RTL of foo is signal a: integer range 1 to 5; function foo_fn(x: integer) return integer is begin report "x'subtype'left=" & integer'image(x'subtype'left) & " x'subtype'right=" & integer'image(x'subtype'right); return(x); end function foo_fn; begin process variable b: integer range 2 to 6; begin wait for 1 ns; report "a'subtype'left=" & integer'image(a'subtype'left) & " a'subtype'right=" & integer'image(a'subtype'right); report "b'subtype'left=" & integer'image(b'subtype'left) & " b'subtype'right=" & integer'image(b'subtype'right); b := foo_fn(b); wait; end process; end RTL; ... # Loading work.foo(rtl) # ** Note: a'subtype'left=1 a'subtype'right=5 # ** Note: b'subtype'left=2 b'subtype'right=6 # ** Note: x'subtype'left=-2147483648 x'subtype'right=2147483647-- Kevin Jennings - 2016-12-19 That's a great example of comments @Ryan #4 and @Ryan #5. (@Ryan #5:) You show that objects a and b can get their ranges (aka attributes, constraints, subtype information) directly from the scalar objects instead of from a scalar type. This means that your proposed section 16.2.3.2 is unnecessary. Also, you show (@Ryan #4) that object b is copied by value into function foo parameter x.
x
is an object of subtype integer. So evaluating its attributes give the range for the integer type. This is why I suggest that your next draft should include changes to 4.2.2.2 where the pass-by-value semantics are given. This will help achieve the effect you were trying to get by modifying the text of the note preceding 4.2.2.2.
-- Ryan Hinton - 2016-12-19
I don't see how you can conclude "This means that your proposed section 16.2.3.2 is unnecessary". The example shows that, within the function, there is currently no way to get at the actual bounds of a parameter (which is what I'm after), so some change is required to implement the proposal. While x'subtype'left returns the bounds of x within the context where x is declared, it does not work inside a subprogram that is called with the parameter set to x. If it did, then the last report statement would have printed "x'subtype'left=2 x'subtype'right=6" rather than printing the bounds of an integer.
The change I proposed is to allow scalar attributes to be accessible and one can access those attributes in the same manner regardless of context and does not break backwards compatibility (i.e. x'subtype'left would still return the bounds of the subtype of the formal when used within a function as it does today). Scalars already have these attributes so that bounds checking can be performed, they are just not called as such in the LRM at present.
-- Kevin Jennings - 2016-12-20
My point is that x inside the function is its own object. Calling x'subtype'left will give exactly the same thing as your proposed x'left. A scalar does not have attributes. It has a value and a subtype. Defining an attribute 'LEFT on a scalar will have to get its "return value" from the subtype of that scalar.
Defining attributes on scalars will not get you the attributes of the formal since constant and variable parameters are passed by value in many cases. You're working on the right problem, but the solution you propose is unrelated.
-- Ryan Hinton - 2016-12-20
RH: Calling x'subtype'left will give exactly the same thing as your proposed x'left. KJ: Not once this LCS gets written up correctly it won't.
RH:: A scalar does not have attributes KJ: But they could have attributes, that's what I'm trying to get added. Putting aside constants and expressions for the moment, a parameter input to a function will have a declaration associated with it. That declaration will define the attributes that are available to be used. The changes I've made to 4.2.2.2 and 4.2.2.3 now address what to do with constants, expressions as well as variables and signals.
RH: Defining attributes on scalars will not get you the attributes of the formal since constant and variable parameters are passed by value in many cases KJ: Did you mean to say formal in the above? If so, then getting the attributes of the formal would be the same as today (i.e. x'subtype'left for example), no change intended. If you meant actual instead of formal, then it's not clear to me how my solution is unrelated. Incomplete or incorrect, OK, but not seeing it as unrelated.
In any case, I've made several edits to address the concerns from you, Ernst and Tristan, summarized along with how I addressed the points in my updated comment above from 2016-12-16. Calling this Version 3. Please review and create new comments below. As you did previously, numbering the issues makes for a handy way to refer to them which in turn helps to get them all addressed.
-- Kevin Jennings - 2016-12-21
RHv3#1 Page 21. I hope one of the tool implementors will chime in here. KJ reply: I agree, Tristan has visited and commented, not sure who are other tool implementors that are in the audience. RH: As far as I know, attributes are never assigned. The attributes come from the subtype. For scalar formals, the subtype of the formal is given in its "declaration" in the interface list. It sounds like what you're asking for is to change the subtype from their declaration. It feels wrong to me to see an input x of subtype integer, but the tool changes its subtype for each call. I suppose it's not that different from what happens with unconstrained array formals. KJ reply: I'm not trying to change anything existing. I'm trying to get information that I know is currently available to the tool by virtue of the existing requirement on the tool to insure that function parameter actuals are within the range of the function parameter formals. I'm trying to use that information to perform something that is new and I think a useful function.
RHv3#2 general suggestion. I suggest you split off the scalar attributes and related changes into an independent LCS. The title of the proposal is "Method to allow functions to know the output vector size." I agree that this would be a great feature to have. I can remember only a handful of times where knowing the input subtype would be similarly useful. Really they are two different changes and deserve to be voted independently. For what it's worth, I like the 'actual and 'formal approach much better -- it seems a MUCH easier change to implement. (I would create one new attribute, 'subtype_actual to get access to the subtype of the actual similar to the current 'subtype which gives the subtype of the formal.) KJ reply: The ideas are a bit more linked than perhaps you've considered. When writing the proposal, and later the LCS, it immediately becomes apparent that one needs to have a mechanism to refer to the attributes of the target itself, not to the type/subtype of the target. What I used here as my mental model, is that the end user should think of the 'target' as being like another input that is available to the function, but an input where the only legal actions are to refer to attributes. The most straightforward way then to get at the length attribute (for example) then would be as "target'length" which would be the exact same form that one would use outside the function. Now, given this model that treats 'target' as being just another (but somewhat restricted) input parameter, it is a small leap to then say that if one were to want to refer to the attributes of the actual (not the subtype of the actual) that one would want to also use the same form "parameter'left". There are proposals such as NewPredefinedAttributeActual that do indicate demand for the same thing that I'm trying to get implemented here in this LCS with function parameters. I think it would be a mistake to require the end user to use different syntax to get at the attributes of the target (which is needed for this proposal/LCS) and the attributes of the parameters passed into a function which is also different than how one accesses the attributes of an object outside of the context of a function. If this LCS was split in two, then there would either have to be a dependency of this LCS on that new LCS (or some alternate proposal/LCS such as NewPredefinedAttributeActual) otherwise one risks coming up with different mechanisms for the end user to simply be able to access attributes of something. I don't think that's a good thing. I do all of this without introducing new keywords unlike NewPredefinedAttributeActual so that's a bonus as well. Because a new keyword is created, NewPredefinedAttributeActual is not going to be backwards compatible and could break existing code (although I admit it is probably not terribly likely).
RHv3#3 Page 21 editorial note. I suggest replacing the colon in the first new sentence with a comma and making the following "If" lower-case. This makes it correct grammatically and follows the pattern of the nearby paragraphs. KJ reply: Fixed.
RHv3#4 Page 21. I don't understand why you have distinct cases for "if the actual is an identifier" and "otherwise." In your big addition for page 20, you specify that only the "otherwise" attributes may be used. KJ reply: What I'm trying to get across is that when the parameter actual to a function is an identified object such as "signal FingerCount: natural range 1 to 10;" then the new attributes that get passed into the function are the attributes of FingerCount (i.e. left=1; right=10). I'm covering this situation with "the attributes of the parameter shall be assigned from the corresponding attributes of the actual". However, if the input to the function is an expression or a literal, then you don't immediately have those attributes. What I was covering with the "Otherwise..." is the case for when a literal is assigned to the parameter. In a sense, the tool is fabricating attributes for the literal in order to be able to pass them into the function, but I think what I specified is straightforward. I do see though that what I have does not cover the case where the function parameter comes from an expression. I'll have to ponder a bit on how to word that and add that into that same area of the LRM. If you have some preferred wording, feel free to suggest something.
RHv3#5 Page 244. You missed red markings on "scalar" in S'LEFT. Also, a scalar subtype doesn't have "ranges"; it has a "range" (singular, not plural). KJ reply: Instnaces of "ranges are" changed to "range is". Twiki keeps mangling and removing font coloring. I found a whole bunch of black font "scalar" that I know had been red. <RANT>I think we would have been far better off using PDF attachments for the LCS as I had originally done and not try to use a tool such as Twiki which destroys things randomly. The coloring is important and Twiki keeps messing it up for no apparent reason. I'm tired of having to recolor things that had been colored.</RANT>
RHv3#6 Page 244. The result type should be the base type of the scalar or scalar subtype. KJ reply: I'm not sure I follow or whether you're referring to all of the result types or just one. In any case, I think what I have is correct since it was based on existing LRM text and simply removing array referencing. Can you clarify a bit about what exactly is wrong? Is it actually 'wrong' or just not how you would word it?
RHv3#7 Section 16 changes. I still object to adding all this text because it doesn't provide anything not already available via S'SUBTYPE'attr. From my best guess of your intent, the subtype of the formal will be the subtype of the actual. So x'subtype'left will still be the same as x'left: both will refer to the subtype of the actual instead of the subtype of the formal (current behavior of the former). KJ reply: With the current LRM, x'subtype'left does not return what is needed, when used within a function. Please refer back to the sample code that I posted. Within the architecture and the process if one has signal xyz: integer range 1 to 5 then x'subtype'left = x'left = 1, but when xyz is passed into a function such as Func(x: integer) as Func(x=>xyz) then x'subtype'left returns the left bound of integer and there is no mechanism for the function to know that the left bound of the actual that is bound to x is actually 1. What I'm adding is that inside a function you will now be able to refer to xyz'left which is currently illegal so there will be no backwards compatiblity issues with doing so. Now it will be legal syntax in a function and will return the left bound of the actual that is assigned to parameter x which, in this case, is the left bound of xyz, which is 1. So this is providing something new and doing so in a way that makes currently illegal syntax legal and useful.
(#7 cont.) Perhaps you're intending x'subtype'left to continue to give the left bound of the subtype of the formal while x'left gives the left bound of the subtype of the actual. KJ reply: If you mean the '1' in signal xyz: integer range 1 to 10; and xyz is passed into a function then YES!" RH: I'll vote against that as against the "do it explicitly" spirit of VHDL. Nothing about x'left suggests to me that the tool is reaching outside the scope of the subprogram to grab attributes from the subtype of the actual. *KJ reply: x'left suggests to me the obvious which is that it is retrieving the left bound of x, not the left bound of the subtype of x. As you've already stated, you like the idea (but not the method) being presented here of being able to access the attributes of the actual and you have had very little use for accessing the attributes of the subtype which was added in 2008. That has been my experience as well. Based on the limited polling of two people, this suggests that what was added in 2008 is possibly of limited use to an end user. I think there is quite a bit of value for the end user in being able to use the exact same syntax (i.e. xyz'left) regardless of the context. It works the same whether you're in an architecture, a process or a subprogram. I can't sway you if your reason is 'against that as against the "do it explicitly" spirit of VHDL' but I will say that reason is not a technical one that can be resolved technically. That will take either gentle persuasion, arm twisting or pistols at 20 paces.
(#7 cont.) An object has a value and a subtype. "An object is a named entity that contains (has) a value of a type." (6.4.1) It does not have a range. (Point me to the LRM if I'm wrong.) KJ reply: But an object also has attributes hence xyz'left does return the left bound of an integer. RH: The text "Left bound of the range of S" is nonsense because a scalar object S has no range defined in the language. These changes reference concepts that don't exist. If you want x'left to return the left bound of the subtype of x (formal or actual), your changes are still incomplete. KJ reply: OK, so taking one sample, can you suggest wording that is correct?
Currently in LCS: "Result type: Type of the left bound of the range_constraint ::= range range range ::= range_attribute_name | simple_expression direction simple_expression(#7 cont.) Arrays are fundamentally different in this respect. A scalar object of an appropriate integer subtype may contain the value 3. 3 doesn't have a range. On the other hand, an object of an appropriate bit_vector subtype may contain the value (4 to 7 => "1011"). An array value obviously has a length. In fact, the LRM gives array values an index range as well, as anyone who's used the fixed_pkg can attest. Scalar values in expressions are handled according to their base type (see the enhanced integer discussions). Array values keep their bounds in expressions. On assignment, an implicit subtype conversion occurs for arrays and a subtype check occurs for scalars (5.3.2.2, 10.6.2.1, 14.7.3.4, etc.). KJ reply: OK, but not seeing the relevance to this LCS so not seeing anything that is actionable here. (#7 cont.) I don't see an easy way to change this difference between array and scalar values. That's why I would prefer a variant of the 'actual attribute proposal ( NewPredefinedAttributeActual). That's why I suggest splitting out the scalar attributes portion of this LCS that is supposed to be about vector sizes. KJ reply: OK, I prefer not to add keywords and possibly break backwards compatiblity and to provide the end user the same syntax to get at attributes regardless of context. Your preference is noted but is not a technical point that I can respond to so I think we will have to simply have to agree to disagree. RHv3#8. You have specified in your page 20 changes when a function with a named return value should be called. This should be done instead by modifying the overloading rules and signature rules in 4.5. Possibly 12.5 may need to be changed also. KJ reply: To be blunt and honest, I don't know what the heck needs to change in order to get across the point that there can be instances where using this new form of function is not allowed. Not asking you in particular to do this, but I've taken two swings at it and missed both times so I think I need some help from somebody to define this limitation properly. RHv3#9 Page 186. I would put the formal return identifier at position (d) in the list next to the formal parameter declaration. KJ reply: I put it at the end of the list so as not to break anything. There are LRM references to some of the labeled bullet items so I would prefer not to insert in the middle and shift the others down and then accidentally miss updating a reference. The list is not a priority order, there is a flow to it, but that flow is cosmetic. KJ general: Thanks for all your input, it is helping. It appears to me that we are having fewer technical objections as the LCS gets revised which is good, progress is being made and hopefully get to a point of no technical disagreements. Can't help much with the non-technical other than to explain my reasoning and thought process. -- Ryan Hinton - 2016-12-21 with KJ replies KevinJennings 2016-12-23 Version 4 created 29-Dec-2016. Changes are: - Wording regarding the context where the new function type may be used. - The section regarding attributes of scalars and accessing them within a function has been moved to a new LCS (LCS-2016-072a). -- Kevin Jennings - 2016-12-30 Version 5 created. Changes are: - Define that the types of targets includes scalar objects. This was inadvertantly dropped when the LCS was split to create LCS-2016-072a. This creates a dependency with LCS-2016-072a. The contingency if LCS-2016-072a is not approved is documented in the notes. -- Kevin Jennings - 2017-01-05 Thanks for re-focusing on the return value. This looks very good now! -- Thomas Preusser - 2017-01-13 Version 6 created, changes are: - Changed 'identifier' to 'return_identifier' - Clarified usage of 'return_identifier' to be as a prefix to retrieve object attributes rather than as a variable that is limited only retrieving attributes - Added RANGE and REVERSE_RANGE to the list of scalar object attributes that can be retrieved. -- Kevin Jennings - 2017-01-16 LCS 072 - ver 6: If the target is an array, the target must meet one of the conditions… PL: You shouldn’t refer to the target and ask if it’s an array. You already know the return type and it’s type class (scalar, array, ...). So your textual case list should use the return type’s type class. E.g. If the return type is an array type, the target should meet one of the conditions ... This particular function, wouldn't be selected, if the return types doesn't match the target type (=> overload resolution). -- Patrick Lehmann - 2017-01-16 Extending on Patrick's last comment, the sentence "If the target is an array, the target must meet one of the conditions…" (page 20) must be reworded at all. It is not the target which can meet one of the cases of `Determinable index range conditions' (9.3.3.3). At the moment, the list defines where an array aggregate with an others choice can be used. Thus, if you want to reuse it, then the list will also define where a function with an return identifier can be called. Just take a look at case f) which reads "as the expression defining the initial value [...]". Thus, the above mentioned sentence in your LCS should be reworded to: If the return type denotes an array type, then the function call shall appear only in one of the conditions of ‘Determinable index range conditions’ as listed in section 9.3.3.3 -- Array aggregates. The list also contains cases, where the target is not an object, e.g., case d). In this case the function can be called as follows:
function f (x : integer) return target : unsigned is begin return to_unsigned(x, target'length); end function f; function g(x : integer) return unsigned(7 downto 0) is constant c : unsigned(7 downto 0) := f(7); -- here the target of f() is an object begin return f(x); -- here the target of f() is a subtype end function g;Thus the prefix "x" in "x'left" in function f may denote a subtype as well. Ok, this example should actually work, because the predefined attributes for arrays are defined for array objects as well as fully constrained array subtypes. The other cases of `Determinable index range conditions’ must be checked as well (maybe I will find some time later on.) I haven't yet checked the conditions when the result type denotes a scalar type because I'm still reasoning about LCS-2016-072a. -- Martin Zabel - 2017-01-21 Version 7 created, changes are: - Changed wording "If the target is an array" to "If return type denotes an array type" to address Martin (and Patrick's?) concern @Martin: - I can't really reference the list from 9.3.3.3 since sub-bullets j) and k) do not apply here. - Your example "function g(x : integer) return unsigned(7 downto 0)" is not legal since the return type must be a type mark not a subtype indication. - To your point about bullet d), in order to get "the corresponding function result type is a fully constrained subtype", one would need to define a new (sub)type that is fully constrained, not use something that is unconstrained like 'unsigned'. In any case, I think bullet d) does apply here for this LCS. -- Kevin Jennings - 2017-02-08 Rev 7 EDIT2: page 20, first paragraph Suggested simplification: The reason the terminal "return_identifier" has a unique name is so you can reference it in the text. Hence, rather than "the name that the function body may reference to retrieve attributes of the target (if any)," you can simply say "return identifier (if any)". Note when you reference a EBNF term, you do not include the "_". Rev 7: Edit 3: the added paragraph on page 20, Potential Issue: I am not sure you can use the term target here as I usually associate that with the target of a assignment, however, I do note type conversions talk about the target of the conversion, so the language appears to have some degrees of freedom here. Suggested simplification: The return identifier allows access to the attributes of target of the function return value. It is an error if the attributes of a return identifier are accessed and the attribute values are not determinable. If the return type is an array type, the attribute values are determinable when the target meets one of the conditions listed in section 9.3.3.3 as "determinable index range conditions." If the return type is a scalar type, the attributes are determinable when the target meets one of the following conditions:
Issue: When is any scalar type not a fully constrained subtype? Objects that are type integer or a subtype of integer when used in an expression have the full range of type integer. Objects that are of an enumerated type can have any value of the enumerated type.
Issue: I don't see any relationship between your long list in blue and LCS_2016_072a. For example, item "a)" talks about actual, but this is not the actual from the perspective of 72a - aka inside the subprogram, but instead the actual that is the target of your return value, and hence, the input to another function. The question "a)" is asking then is, since the constraints of the actual/target/return identifier are unknown can we determine them by looking at the formal parameters of the subprogram being called.
It is not clear that "d)" applies here since we are talking about our output and "d)" talks about the output of some other function.
edit 4: LRM 9.3.3.3 Text needs some work.
Edit 5 12.2. Scope page 186 Issue: Not needed here. The reason parameters of subprograms are on this list is to allow you to reference the parameter name in a named association - which is outside the scope of the subprogram. Everything I have seen of your use model only used the return identifier inside of the function itself. This is already within the scope of a subprogram - by the first sentence of the paragraph that precedes the list.
-- Jim Lewis - 2017-02-09
JL: "the name that the function body may reference to retrieve attributes of the target (if any)," change to --> "return identifier (if any)"
KJ: Agreed.
JL: "If the specification of a function includes..." (entire added paragraph) change to --> "The return identifier allows access to the" (entire paragraph)
KJ: Agreed.
JL: When is any scalar type not a fully constrained subtype?
KJ: Good point. Given that, I'm thinking the blue font stuff should be completely stricken, there are no special conditions that must be met if the target is a scalar. It does bring up a question regarding the interaction with LCS-2016-18: Given this...
function foo(x: integer) target return integer; variable foo_out: integer range 5 to 10; foo_out := foo(x);According to LCS-2016-018, inside function foo, what would target'left evaluate to? Would it be 5 because that is the 'left of the actual? Or would it be integer'left because the function definition does not explicitly define a smaller range? Getting 5 was one of the reasons in my mind for needing 72a. My interpretation of LCS 18 is that since target'left is equivalent to target'subtype'left then that it would evaluate to integer'left since target is defined as 'integer' with no explicitly defined range...which is not what would be desired here. To be useful, one would want target'left to get at the attribute of the 'actual' again...which is what 72a is all about. JL: LRM 9.3.3.3 Text needs some work. KJ: Anything in particular? JL: Scope page 186 Issue: Not needed here... KJ: Agreed, will remove the changes to 12.2. Thanks for the input. -- Kevin Jennings - 2017-02-09 KJ: According to LCS-2016-018, inside function foo, what would target'left evaluate to? MZ: Of course, foo_out'left which is 5. To cite from your own LCS: "The attributes returned are the attributes of the target to which the output of the function is assigning." The target is an object and, thus, LCS-2016-018 is required to retrieve attributes like 'left from objects. If LCS-2016-018 is not approved, then this LCS cannot retrieve the attributes from the target. KJ: My interpretation of LCS 18 is that since target'left is equivalent to target'subtype'left then that it would evaluate to integer'left ... MZ: The attribute SUBTYPE is defined only on objects, thus this attribute can be taken only from the target, not from the return type. But then, target'subtype is "integer range 5 to 10" and thus target'subtype'left is 5 again. At the moment, target'subtype is not allowed by the LCS. This is ok, because otherwise the interference with clause 5.3.2.2 has to be checked, see definition of 'subtype. KJ: Getting 5 was one of the reasons in my mind for needing 72a. MZ: LCS-2016-072a is about retrieving attributes from actuals associated with subprogram parameters. It is not about retrieving attributes from the target. These two aspects are completely different. I haven't yet completed my review of version 7. Thus, my vote is not updated. -- Martin Zabel - 2017-02-09 Martin, thanks for clarifying. -- Kevin Jennings - 2017-02-09 Splitting the original LCS into two definitely helps to clarify intent, and several of my previous objections no longer apply. I share JL's concerns about the use of the term "fully constrained subtype" in the blue list, but I disagree with KJ's statement that "there are no special conditions that must be met if the target is a scalar", at least not with the formulation in V7. Let's assume that we have function foo as defined by KJ on 2017-02-09. The question arises what an attribute x'left would return if f is called in an expression of the form term1 + f(3) (or similar forms). "Target" doesn't have a meaning here as it's a concept related to an assignment statement. I see two ways to address this concern
Regarding the proposed LRM text, a few suggestions:
-- Ernst Christen - 2017-02-10
@Kevin, to check whether the "Determinable index range conditions:" from clause 9.3.3.3 can be re-used, I have prepared 2 VHDL files and attached them to this topic. The file use_of_others.vhdl demonstrates where "others" can be used according to clause 9.3.3.3. The file application_of_lcs072.vhdl replaces these "others" by a function call which would know the target size (based on this LCS).
EDIT: The main observation is: Not the target must meet one of the conditions of "Determinable index range conditions." It is the function call itself. That is, the list can be reused if it is preceded by "The function call shall appear only in one of the following contexts":
Example:
The function call shall appear only in one of the following contexts:
Thus, the target is almost a "fully constrained array type".
I want to point-out 2 unusual use cases which are allowed due to clause 9.3.3.3:
*END OF EDIT*
I haven't reviewed the blue text because according to your answer to Jim (2017-02-09), the blue text is likely to be removed.
-- Martin Zabel - 2017-02-12
Version 8 created to address comments from Jim, Ernst and Martin. The biggest change is to remove the list that was referenced from 9.3.3.3 and instead replace it with something much simpler. For array types, the allowed context where the function can be used is when the target of the function is declared with either an explicit range constraint or has a default initial value assignment. I think those are the only two cases where one can end up with a target that one can retrieve the needed attributes. For scalars, there are no constraints.
-- Kevin Jennings - 2017-02-14
*Regarding Version 8:*
@Kevin, the LCS is better now, but it seems that you missed the point from my comment on 2017-02-12. If you want to read attributes from "the object to which the output of the function is assigning", then the context rules have to ensure that
For example, if you want to use such a function call for the default expression or in an assignment, the first additional paragraph on page 20 must read as follows (red are your additions, blue are my modifications):
The return identifier allows access to the subtype of the target of the function from within the function body. The only allowable action within the function body with return identifier is as a prefix to read object attributes. The attributes returned are the attributes of the object to which the output of the function is assigning. The function with return identifier shall only be used in one of the following contexts:
You may add further items from the determinable index range conditions from clause 9.3.3.3. I am not sure about signal objects at the moment, because item g) in that list talks about the corresponding subtype. But why?
-- Martin Zabel - 2017-02-15
@MZ: The two conditions that I listed for the allowable contexts in Version 8 are mutually exclusive and define the two conditions where I want to define the specific context where the new form of function can be used (i.e. "If type mark is an array type" and "If type mark is a scalar type"). I think that the two conditions that you listed overlap since an expression involving an initial value (your 'a' condition) is a form of assignment statement (your 'b' condition). That then causes you to have to say "one of the following contexts" prior to the conditions, but I don't think you clearly say how to select which one. I do like your wording of "fully constrained array type" rather than my "object with an explicit range constraint or an object with a default initial value assignment" which is incorporated into Version 9 which is now available.
-- Kevin Jennings - 2017-02-16
Version 9 created, changes are:
- Page 20 paragraph: Expanded that target can be an "array or scalar object or scalar expression"
- Page 20 "If type mark is an array..." condition reworded to say "fully constrained array type" rather than "object with an explicit range constraint or an object with a default initial value assignment"
-- Kevin Jennings - 2017-02-16
Version 10 created. Changes are a rewrite to 'Page 20' which defines the allowable contexts that can use the new type of function.
-- Kevin Jennings - 2017-02-24
Please remove or broaden the restriction for attribute applications on the return identifier. This should be aligned with other LCS to allow e.g. attributes for returned access types.
The list of attributes for scalars includes common attributes like BASE and SUBTYPE. By adding these to the scalar list, they are not usable with array return types. I suggest to create a separate paragraph for all return types (BASE, SUBTYPE), or list them for array types to.
The list of scalar types lists e.g. RANGE, but not LENGTH.
-- Patrick Lehmann - 2017-03-14
Version 11 created to add BASE, SUBTYPE and LENGTH attributes as listed in Patrick's comment above.
Not sure which LCS you are referring to just yet about expanding the scope for access types. Will look again later.
-- Kevin Jennings - 2017-03-14
Review: 1) Page 20 first paragraph:
type complex is record n : unsigned ; i : unsigned ; end type complex ;3) 2nd constraint: why not just:
type complex is record n : unsigned ; i : unsigned ; end type complex ;Then using the return identifier one can say:
function FlintStone (A, B : complex) return RtnVal : complex is variable result : complex( n(RtnVal.n'range), i(RtnVal.i'range) ) ; begin . . . return result ; end function FlintStone ;-- Jim Lewis - 2017-03-16 @Jim: Your definitions do not define what the prefix represents in all of your 4 cases. -- Martin Zabel - 2017-03-16 @Jim: The term "target" is defined only for signal and variable assignment statements, see clause 10.5 and 10.6 which define and use the EBNF for "target". -- Martin Zabel - 2017-03-16 @MZ It is late, but here is an attempt at a correction to my suggested edit: The return identifier denotes the subtype of the return expression. When a function that uses the return identifier to determine the subtype is called, the subtype of return expression may be determined from the context of the call when the return expression is used: a) as the expression following the ":=" in a constant, variable, or signal declaration and the corresponding declaration is a scalar or fully constrained composite type,
architecture a of e is function f(x : integer) return integer; -- function declaration function f(x : integer) return integer is -- function body begin return x; end function; constant c : integer := f(x => 1); -- extended scope begin end architecture;The formal parameter "x" is declared immediately in the declarative region of function "f". And this declarative region includes the function declaration and function body of "f" due to clause 12.1. Thus, the immediate scope of "x" starts with the declaration of "x" and ends with the function body of "f" due to clause 12.2 (2nd paragraph). But the formal parameter "x" is also required outside the immediate scope, e.g., in the initial expression for constant "c" above. And that's why it is listed in the enumerated list on page 186 (clause 12.2). But the visibility is still limited due to the enumerated list of clause 12.3 (specifically item j). The return identifier must not be visible outside of the declarative region of function "f". Thus no changes are required for clause 12, please remove them from your LCS. The LCS Version 12 does not really state that the return identifier is actually an alias declaration. I think you should reword this sentence: If the above conditions are met, then the return identifier is an alias for the subtype T. To: If the above conditions are met, then the return identifier declares an alias for the subtype T._ -- Martin Zabel - 2017-03-16 Version 13 is available: Changes are: 1. Slight rewording of bullets a) and b) in the changes for "Page 20 Add after the first paragraph" 2. Slight rewording of the sentence that begins "If the above conditions are met..." in the section "Page 20 Add after the first paragraph" 3. Removed SUBTYPE as an available attribute. Not needed because 'return identifier' is a subtype. 4. Removed all changes to clause 12 that were recently added per Martin Z's analysis and recommendation in the previous comment. -- Kevin Jennings - 2017-03-16 This is a technical review of version 13. While I am ok with the concept of 72, I cannot vote yes on the current version until the following issues are addressed. 1) "A function call with a return identifier" A function declaration has a return identifier, a function call does not. 2) "A function call with a return identifier shall appear only in one of the following contexts" Hence, if a function is declared with a return identifier, but does not use it, and it is not called in one of the stated contexts, it is an error. 3) Is the return identifier a subtype or an object? The LCS seems to sometimes say it is a subtype and sometimes an object. It cannot be an object. Functions do not return objects. They return a value. Hence, it can only be a subtype. 4) Is a return identifier an alias? An alias is created with an alias declaration. If you want it to be an alias, you are going to have to provide an implicit transformation of some sort. 5) Since a simple_name denotes a subtype and not an object, one should be able to use any attribute that is appropriate for a subtype. There is no need to enumerate what is and what is not legal for a subtype. When you do this, you are simply duplicating information that is elsewhere and is more appropriately elsewhere. Going further, when you specify the exact attributes you allow, you leave out things like RetID 'simple_name. The reason you had people demanding that you list out the attributes is because various revisions of LCS 72 have incorrectly referred to the return identifier as an object. 6) We should not try to identify what types are legal for the return identifier, instead, we identify when it is illegal to use the return identifier. IE. it is an error if the return_identifier is used to access a subtype constraint for a subtype that is unconstrained. 7) Lets assume that we allow RetID 'simple_name, LCS 72 forbids its usage unless the subtype is determinable from context. -- Jim Lewis - 2017-03-19