|
LCS-2016-060 |
|
1 {06-Jan-2017} 2 {10-Jan-2017} |
|
10-Jan-2017 |
|
Voting |
|
Patrick Lehmann |
|
Main.PatrickLehmann |
|
New Predefined Attributes: 'actual, and 'formal |
|
Adds attributes to access attributes of an actual. |
'ACTUAL_SUBTYPE
to 'ACTUAL
.
P'ACTUAL | Kind: | Subtype |
Prefix: | Any prefix P that is an interface object. | |
Result: | The subtype of an actual associated to a formal. | |
Restrictions: | This attribute is allowed only as the prefix of the name of another attribute; for example, P'ACTUAL'LEFT. |
function foo(s: std_logic; v: std_logic_vector) return integer is variable a, b: integer; begin a := v'left; -- This is how one retrieves the left bound of a vector b := s'actual_subtype'left; -- This is how one retrieves the left bound of a scalar return(a); end function foo;The user will, I think, rightly look at this and question why in the world is there so much typing in order to get the left bound of a scalar when it is so straightforward to get it for a vector? They will also have a valid beef about lack of consistency. There was precedence in how to get the attributes of a vector, how come that same mathod wasn't chosen for scalars? The users (and the tool makers) ultimately bear whatever convenience or burden the LRM puts on them. I think that once a person understands what 'bounds' are, that one has a mental model of what it means to talk about the 'bounds of a scalar' and the 'bounds of a vector' and would probably find it intuitive to access the 'bounds' of scalars and vectors in the same way. The less frequent user would be rightly ticked off that they need to use different methods to get at what they consider to be the same type of thing...after having to go back to the 'Dummies' book to see once again how to get the left bound of a scalar again. My two cents is, if you vote for this proposal, I think you should be comfortable explaining your answer to an end user to the question "Is this really the best that can be done here? Really???" I'm not trying to get into a debate on this and, as I said it is non-technical, just putting it out there asking people to consider the end user's view and how this feature could very likely be perceived out in the world. I'm not trying to go all 'Marketing' on folks, but this one doesn't look pretty to an end user and it easily could have. Plus we are all end users as well, do you really want to be accessing scalars and vectors differently when you're writing code? -- Kevin Jennings - 2017-01-06 I'll think about your notes and maybe come up with some improvements, but just for now, this LCS is a basis for the LCS 072 series, right? For your example, if
v
is a constrained vector, which is mostly the case on entity port lists, then v'ACTUAL_SUBTYPE'LEFT
can refer to the actual's bounds, whereas v'LEFT
returns the bounds of the formal. Both values might be different.
The difference is not the handling of attributes for arrays and scalars. The difference is that array bounds can be moved in an assignment and association, whereas type ranges
can not be moved. But this is all independent on how you access the information. 'LEFT
for scalar and arrays is not semantically the same operation. It just happens that both
attributes have the same name, because they are defined on different types.
-- Patrick Lehmann - 2017-01-07
While it appears that this feature can be implemented technically, I have a hard time identifying its utility. Isn't it that function or entity interfaces simply use what they
need? If the interface is constrained, you have successfully grounded the uncertainty of direction and concrete bounds. What is the use case for recovering it? If a function is to
behave slightly differently if the actual ranges of its parameters vary, shouldn't it be generic with different instantiations using the appropriate subtypes?
-- Thomas Preusser - 2017-01-10
While the presented attribute works on any type, the major use case is for scalar types. It's are requirement for the LCS 072 series. In FunctionKnowsVectorSize, a function can no
access range constraints of an associated actual, because all attribute are applied to the type of the formal, so for example if you pass in a paramter X of subtype integer range 0 to 7,
then X'high will result in INTEGER'high and not to 7.
-- Patrick Lehmann - 2017-01-10
Reviewing the LCS072(a) documents, it appears that they have both diverted and extended the original goal of the proposal significantly. It is only those scalar extras that may motivate
this LCS. The scalar extras of LCS072(a) also appear to be limited to signal parameters, which appears to me to have a very confined use scenario and hence little impact whatsoever.
This LCS, on the other hand, makes scalar attribute inheritance a general feature, which might even impact compilation times on a broad scale as each call of a function with subtypes may
require its own full elaboration run. The re-use of intermediate compilation results is complicated as the invariance with respect to inherited attributes must be proven by the compiler.
In any case, I cannot find a convincing practical use case neither here nor there. Circular references to the mutual other LCS would not be helpful either.
-- Thomas Preusser - 2017-01-10
TP: The scalar extras of LCS072(a) also appear to be limited to signal parameters
KJ: Not intentionally, it is supposed to cover variables as well.
TP: In any case, I cannot find a convincing practical use case neither here nor there.
KJ: One use case would be when implementing a function that provides some modulo arithmetic functionality before returning a value out the function. By virtue of LCS 72, the function
would be able to access the attributes of the target of a function. By virtue of LCS 72a (or LCS 60), scalars would now have attributes so the 'wrapping around' part could be implemented
with an 'if' statement that uses target'low, target'high. A related example would be to provide upper and lower limits that are defined by target'low and target'high rather than wrapping.
-- Kevin Jennings - 2017-01-10
KJ: Sorry for being annoying but I am still not convinced.
#1: I suppose attributes are also to be propagated to constant parameters then? In the end, this is the default input class and probably the most frequently used one in actual function
implementations.
#2: Even though your example builds some scenario aiming to render the propagation of scalar attributes useful, it still follows the idea of the original proposal to make result properties
accessible to function implementations. It may be a good idea to regularize everything and extend this notion of attribute propagation to the parameters of all interfaces, subprograms
or entities. However, this is a drastically broader modification that should be motivated by a convincing use case. I would also feel much more comfortable with this extended version if
tool vendors indicated that the implicit generic subtyping implied by this modification will not notably effect simulation performance.
-- Thomas Preusser - 2017-01-10
'ACTUAL
should be restricted to interface objects
of scalar types or subtypes.
I think the description of the return value should be changed to that of O'SUBTYPE
:
"The fully constrained subtype that is the subtype of O, together with
constraints defining any index ranges that are determined by applica-
tion of the rules of 5.3.2.2. (If O is an alias for an object, then the
result is determined by the declaration of O, not that of the object.)"
Note: I prefer 'ACTUAL_SUBTYPE
.
-- Martin Zabel - 2017-01-11
Function interfaces regularly comprise constant
parameters. These can be associated with literals, which are formally typed as universal_(integer|real)
. Is there any sensible interpretation of the attributes accessible through 'actual
in this case?
-- Thomas Preusser - 2017-01-13
Noting that implementing this LCS there are new problems presented to the user. In my opinion, avoiding the creation of new hassles for an end user should be a strong consideration.
- New error condition is introduced.
signal S: natural range 3 to 8; constant Sleft: integer := S'actual'left; -- This is a new error condition since S is not an interface object. User needs to remember to NOT use 'actual here constant Sleft: integer := S'left; -- This will be allowed by LCS-2016-018.- Creates an unreported user design issue when code gets refactored because of sensitivity to context. Consider if the user decides to refactor their code a bit and move the 'Sleft' out of the architecture and into a procedure. Furthermore, the procedure is applicable to the full range of type natural. Copy/paste refactoring would likely produce:
signal S: natural range 3 to 8; ... Call the procedure foo as foo(S); ... procedure foo (signal S: natural) is constant Sleft: integer := S'left; -- This form is now 'wrong' since it will return 0 rather than the value 3 from the actual. constant Vleft: integer := V'left; -- This is correct and returns the value 7 from the actualThe above will compile without error but will not produce the same value of 3 for Sleft as it did before refactoring. Instead, the user must now modify their previously working code and instead use S'actual'left. But since there was no compiler error produced, the user is likely to have to debug in simulation to find the error. - Vector and scalar usage is different for no apparent reason to the end user.
signal S: natural range 3 to 8; signal V: std_ulogic_vector(7 downto 0); procedure foo (signal S: natural; V: std_ulogic_vector) is constant Sleft: integer := S'actual'left; -- Why is it that I need to say S'actual rather than S... constant Vleft: integer := V'left; -- when you could figure out what I wanted for a vector???Alternatives: Neither of these end user problems are encountered if LCS-2016-072a is implemented instead. - No new errors are produced - S'left will work properly in all of these contexts without the end user having to make any code adjustments and without having to know which context they are in. - No debug required when copy/pasted code is refactored and the code context changes and yet no errors are reported. I think the basic problem here is that folks are clinging to attributes and how they are used today and thinking that there must be something 'different' in the code in order to distinguish the new usage. What you should consider instead is what do you think the end user should expect to get when they say "Sleft = S'left"? Then ask why they should have to alter their code based on code context to get what they want? -- Kevin Jennings - 2017-01-16 TBP: Function interfaces regularly comprise constant parameters. These can be associated with literals, which are formally typed as universal_(integer|real). Is there any sensible interpretation of the attributes accessible through 'actual in this case? PL: Each literal is implicitly converted (before ?) association. As far as I understand this, the literal (actual) gets the subtype (and bounds) of the formal. -- Patrick Lehmann - 2017-01-16 @KevinJennings PL: I think we are going a bit off-topic here ... I is not a languages concern how a user or his IDE refactors the code! VHDL is still a strong typed language with mostly very precise rules and not JavaScript. So the user must know some specifics about the used statements, objects and types. PL: It's wrong to assume that scalar values and arrays should behave in the same way. One is an atomic type, the other one is a composite type. It is also wrong to assume a similar behavior for an attribute like
'LEFT
, just because the authors chose to use the same name for two different things. One is a scalar type's range boundary and the other one is an array index's range boundary.
PL: As far as I understand the LRM, objects are already classified in interface objects and locally declared objects, so it is not difficult to track if 'actual
is allowed.
-- Patrick Lehmann - 2017-01-16
PL: Each literal is implicitly converted (before ?) association. As far as I understand this, the literal (actual) gets the subtype (and bounds) of the formal.
TBP: The very purpose of using 'actual
is to give you access to the situation before this conversion. And I am afraid, there is no such intuitive before in the case of constant literals. So as to avoid diversion among implementations, a clear specification is needed. Acceptable choices may be (a) to disallow 'actual
on constant parameters, (b) to make the actual subtype equivalent to the formal subtype or (c) to create an implicit one-element subtype of the formal whose range coincides with the exact constant value. As I am still short of a convincing use case, I do not know which of these choices fits best.
-- Thomas Preusser - 2017-01-16
As the 'actual
is not as firmly defined as it may appear at a first glance (see above), specifications are required to eliminate uncertainty and prevent tool divergence. Without an illustrative example that helps to understand the usage scenario, those specification choices can only go wrong. That's why I have changed my vote to a straight no and would ask for postponing this LCS until real demand and well-understood usage patterns become available.
-- Thomas Preusser - 2017-01-17
Even with LCS-2016-018, attributes like 'LEFT can be only retrieved from objects or subtypes, but not from expressions. But, according to clause 4.2.2.1: "The actual designator associated with a formal of class constant shall be an expression." For parameters of class signal, variable or file, there is no problem, because these parameters must already be associated with objects.
For functions which access the attribute 'ACTUAL of the formal parameter, the associated actual designator shall be a name denoting an object. Such formal parameters cannot have a default expression.
I have posted a similar comment below LCS-2016-072a because it has the same problem.
-- Martin Zabel - 2017-01-21