Re: [sv-bc] Serious issue with default expressions for task and function arguments

From: Greg Jaxon <Greg.Jaxon_at_.....>
Date: Fri Mar 04 2005 - 14:49:10 PST
AH!  I see what you're saying now.  Indeed, in C++, the default
argument expression is NOT part of the function's type signature.
In this way it is possible for one function to have multiple APIs
with different default values.

However,
  "The  names  in the expression are bound, and the
   semantic constraints are checked, at the point where the default argu-
   ment  expression  appears."
http://cs.calvin.edu/books/c++/C++Standard-Nov97/decl.html#dcl.fct.default

The other part of your concern appears as:
C++ (Nov'97; intro)
14[Note:  the evaluation of a full-expression can include the evaluation
   of subexpressions that are not lexically part of the  full-expression.
   For  example,  subexpressions  involved in evaluating default argument
   expressions (_dcl.fct.default_) are considered to be  created  in  the
   expression  that  calls  the function, not the expression that defines
   the default argument.  ]

So what you say is absolutely true about C++.
With interface functions, you'd like the default argument expression
to be compiled (names bound) in some client-specific context, which
would allow further specialization of its API, while still invoking the
same function.

I think compiling once per call site may be excessive, but I haven't
thought of any alternative so far.  I'd like to note that writing an
API with open-ended references is a violation of conventional rules
of encapsulation.  If this is worth allowing, then I suggest the following
treatment:

    If an identifier used in a default argument expression of a function or
    task prototype is defined in the scope of the enclosing module, modport,
    or interface, then it becomes bound to that symbol.  If no such binding
    exists, it becomes a free variable and will be bound at each call site
    that uses that default expression.

    Prototypes with such free variables must be noted by a warning or informational
    message, since their API is not completely self-contained.

This is not my "home" chapter in the LRM, so feel free to wordsmith.


Arturo Salz wrote:
> Gord,
> 
> Perhaps you misunderstood the point I was trying to make.
> In my example, there is only one C::F() function, *not* two 
> functions a you seem to suggest. There are two invocations
> (function calls) of the same function. Note that the outcome
> of my example is the same if I change my code as follows:
> 
> === file C.h ===
> 
> class C {
>   public:  static int F( int y = A );
> };
> 
> === file C.cpp === (this is a new file)
> 
> #define A 0
> #include "C.h"
> int C::F( int y )  { return( y + 1 ); }
> 
> ===
> 
> Now, it is very clear that only the function prototype is being
> `included in each of the c files (A.cpp and B.cpp), and there
> is only one C::F() function. What is different is the binding of
> the default expression at each call site. This is not just lexical
> binding.
> 
>     Arturo
> 
> ----- Original Message ----- 
> From: "Gordon Vreugdenhil" <gordonv@model.com>
> To: "Arturo Salz" <Arturo.Salz@synopsys.COM>
> Cc: "Mark Hartoog" <Mark.Hartoog@synopsys.COM>; <pgraham@cadence.com>; <ieee1800@eda.org>; <sv-bc@eda.org>
> Sent: Thursday, March 03, 2005 11:40 AM
> Subject: Re: [sv-bc] Serious issue with default expressions for task and function arguments
> 
> 
> Arturo, you are using the equivalent of 'include to create
> *different* functions in *different* contexts.
> 
> If you want to 'include a function in two different contexts
> in SV, I would expect the binding as you describe as well.
> 
> Consider the following which is the same as the SV examples
> that I brought up:
> 
> class C {
>    static const int A = 1;
>    public:  static int F( int y = A )  { return( y ); }
> };
> 
> main() {
>    const int A = 2;
>    cout << C::F() << endl;
> }
> 
> 
> In this example, C++ will correctly bind the "A" in the default to
> the one that exists in the context of F's definition.  Same thing
> happens if you have:
> 
> static const int A = 1;
> class C {
>    public:  static int F( int y = A )  { return( y ); }
> };
> 
> main() {
>  
>       const int A = 2;
>     cout << C::F() << endl;
> }
> 
> 
> 
> If you 'include a function "F" into two different SV contexts,
> you also get two functions with two sets of bindings.  I have
> no problem with that.
> 
> Gord.
> 
> 
> 
> Arturo Salz wrote:
> 
> 
>>Gord mentions that binding different default values to different calls 
>>of the same function depending on the context of the call may be 
>>unreasonable and not in the context of separate compilation. However,
>>that is precisely the situation in C++. Consider the example below, which
>>generates the following output when run:
>>    foo: 2
>>    bar: 11
>>In this case, function C::F() uses different default values, depending on
>>the context of the call (more precisely the context of the compilation unit).
>>While I do agree that it may not be good coding practice, I do not believe 
>>it should be deemed unreasonable. Also, since C++ does allow separate 
>>compilation, it is definitely reasonable in that context: Proof by existence.
>>
>>    Arturo
>>
>>=== file C.h ===
>>
>>class C {
>>  public:  static int F( int y = A )  { return( y + 1 ); }
>>};
>>
>>=== file A.cpp ===
>>
>>#include <stdio.h>
>>static const int A = 1;
>>#include "A.h"
>>
>>void foo() { printf( "foo: %d\n", C::F() ); }
>>
>>=== file B.cpp ===
>>
>>#include <stdio.h>
>>static int A = 10;
>>#include "A.h"
>>extern void foo();
>>
>>void bar() { printf( "bar: %d\n", C::F() ); }
>>
>>main()
>>{
>>    foo();
>>    bar();
>>}
>>====
>>
>>    Arturo
>>
>>----- Original Message ----- 
>>From: "Mark Hartoog" <Mark.Hartoog@synopsys.COM>
>>To: <pgraham@cadence.com>; <gordonv@model.com>
>>Cc: <ieee1800@eda.org>; <sv-bc@eda.org>
>>Sent: Thursday, March 03, 2005 10:39 AM
>>Subject: RE: [sv-bc] Serious issue with default expressions for task and function arguments
>>
>>
>>
>>
>>>In this case there is no p1 visible at the point of compilation
>>>of function f.  Is this legal?  Is SV adopting dynamic scoping? :-)
>>
>>
>>The LRM says "The elements of the expression must be visible at the scope 
>>of subroutine". In your example, 'p1' would be an unresolved identifier
>>in the scope of the subroutine, so this would be illegal.
>>
>>I think part of the confusion here is what the term "elements of the 
>>expression" means. When you have an expression like 'p1', I think the 
>>element of the expression is the object that the identifier 'p1' resolves
>>to in that scope. Other people seem to think that the element of
>>the expression is simply the identifier itself. Perhaps this needs to 
>>be reworded to make clear what was meant.  
>>
>>
>>
>>>-----Original Message-----
>>>From: owner-sv-bc@eda.org [mailto:owner-sv-bc@eda.org]On Behalf Of Paul
>>>Graham
>>>Sent: Thursday, March 03, 2005 10:24 AM
>>>To: gordonv@model.com
>>>Cc: ieee1800@eda.org; sv-bc@eda.org
>>>Subject: Re: [sv-bc] Serious issue with default expressions for task and
>>>function arguments
>>>
>>>
>>>
>>>
>>>>   The default_value is an expression. The expression is evaluated in
>>>>   the scope of the caller each time the subroutine is called. The
>>>>   elements of the expression must be visible at the scope of subroutine
>>>
>>>Here's another example:
>>>
>>>function f(integer x = p1);
>>>  return x;
>>>endfunction
>>>
>>>module m1(...);
>>>   parameter p1 = 1;
>>>   assign q = f(); // q == 1
>>>endmodule
>>>
>>>module m1(...);
>>>   parameter p1 = 2;
>>>   assign q = f(); // q == 2
>>>endmodule
>>>
>>>In this case there is no p1 visible at the point of compilation
>>>of function f.  Is this legal?  Is SV adopting dynamic scoping? :-)
>>>
>>>Paul
>>
>>
>>
> 
Received on Fri Mar 4 14:49:22 2005

This archive was generated by hypermail 2.1.8 : Fri Mar 04 2005 - 14:49:31 PST