RE: further discussion on implications of typing rules

From: Bob Shur <shur_at_.....>
Date: Tue Jun 26 2007 - 19:08:59 PDT
Thanks, John, for the patience and clarity that it took to explain this
(again).
 
I accept the requirement that you should not be able to circumvent
strong typing by going outside of a language.
 
I also accept the observation that doing automated conversions is a bad
idea, except under a finite number of specified circumstances.
 
If I'm reading your message correctly, it seems that an oversimplified
way to illustrate the main point is that this Verilog should be
outlawed:
 

	typedef enum { red, green, blue, yellow, white, black } Colors;
	Colors c;
	c =
<reference_to_some_VHDL_or_SC_thing_of_a_temptingly_similar_looking_enum
>;
	

I agree. There's still the question of what to tell the user to do
instead. This is where my comments about needing a way to supply
conversion functions comes in. It is possible to write a Verilog
function to make this work:

	
	typedef enum { red, green, blue, yellow, white, black } Colors;
	Colors c; 
	typedef enum { green, yellow, red, blue, white, black }
ReorderedColors;
	ReorderedColors r;
	...
	c = convert_colors(r);
	 

The function would look something like:

	 
	function Colors convert_colors(input ReorderedColors r) ...

It would be nice if something similar were possible for converting
between SC/VHDL/Verilog types. I don't have a good answer for what it
looks like, though. There's no way to write such a conversion function
in any one language. I suspect the conversion would end up being in
C/C++ with each language having ways to pass things to/from C/C++.
 
I think that the kind of mixed designs you focus on determines whether
the conversion functions are regarded as a nice thing to consider
someday or an urgent capability. If you're mostly worried about passing
class objects around, then life will be hard without conversions.
 
If and when we figure out how to write the conversion functions, then it
might be reasonable to say that you can connect a Verilog reg of type
Colors to a VHDL port of type SimilarColors, provided that you have
written the appropriate conversion functions.
 
Just to clarify, I still agree with your requirements. Conversion
functions, if they exist, should only be able to do the same kinds of
things that could be done anyway within the language.


________________________________

	From: owner-sv-xc@eda.org [mailto:owner-sv-xc@eda.org] On Behalf
Of John Shields
	Sent: Tuesday, June 26, 2007 5:51 PM
	To: Bob Shur
	Cc: sv-xc@eda.org
	Subject: Re: further discussion on implications of typing rules
	
	
	Hi Bob,
	
	Thanks for taking the time to do this.  Because there is no
proposal and only arguments presented for a requirement,it is
understandable that one might have questions. I don't want you to agree
to something out of a misunderstanding. Wanting some examples to
illustrate the requirement makes sense.  As long as we don't go down a
rathole of needing to see the answer for every type or related use case
in order to accept the requirement, we are being smart.  After all,
requirements serve to guide the formation of the spec, to analyze all
the details, and evaluate afterwards whether we achieved what we wanted.
	
	I'll try to get at your questions from the simplest of the
strong types and perhaps the one that defies the desires of users who
want the languages to do what they mean.  I apologize for the length of
this email as it is partly a style problem of mine.  I hope it sharpens
the argument.  I also hope it addresses the comments that Michael
Rohleder made in reply to your email.
	
	It is typical that well-known built-in types can be weakly typed
and support automatic conversions between them that make sense.  It is
also typical that user defined types like enumerations, structures, and
classes are strongly typed and there are no automatic conversions
between them, except for conversions written by the creator/user of the
types.  For some types, the discerning author may say there is a
possible analysis that would allow an automatic conversion and a
check(possibly runtime) to validate whether the result is legal.  For
other types like unrelated class types, it is mostly obvious that it is
not possible to infer any reasonable automatic conversion.  No matter.
The languages deny automatic conversion.  Period.
	
	In SV, enumerations, structures and classes are strong types.
It is generally easy to make the argument for classes that they are
distinct types and, if they are not related by inheritance, that it
makes no sense to allow assignments of one class type to an object of
another class type.  Let's look at enums and see how SV makes its
argument. We can then easily see the same argument for structs and
classes. An enumeration type is an integral type that has a user-defined
set of named constants.  An integral type is one of SV's basic integer
data types or packed data types that can be treated as an integer. SV
provides rules for automatically defining the encoding of enumeration
constants and also allows user-defined encoding.  The values may be
disjoint.
	A couple of examples are:
	
	enum {red, yellow, green} light1, light2; // anonymous int type
	// c is automatically assigned the increment-value of 8
	enum {a=3, b=7, c} alphabet;
	
	There are richer examples of the flexibility of SV enumerations.
What does SV say about strong typing and enumerations?
	
	6.17.3 Type checking
	Enumerated types are strongly typed; thus, a variable of type
enum cannot be directly assigned a value that
	lies outside the enumeration set unless an explicit cast is used
or unless the enum variable is a member of a
	union. This is a powerful type-checking aid that prevents users
from accidentally assigning nonexistent values
	to variables of an enumerated type. The enumeration values can
still be used as constants in expressions,
	and the results can be assigned to any variable of a compatible
integral type.
	...    
	Enumerated variables are type-checked in assignments, arguments,
and relational operators. Enumerated
	variables are auto-cast into integral values, but assignment of
arbitrary expressions to an enumerated variable
	requires an explicit cast.
	
	Despite the fact that one can view an enumeration's value as an
integer, one cannot make an assignment to an object of enum data using
an integer value.  It doesn't matter that it is in range or corresponds
to one of the enumeration constant's value. So, 
	
	typedef enum { red, green, blue, yellow, white, black } Colors;
	Colors c;
	c = green;
	c = 1; // Invalid assignment
	
	It doesn't matter that green and 1 have the same value.  If I
declare a different enumeration that is similar to colors in form and
meaning(at least to me the author), I run into the same restriction,
right?
	
	typedef enum { m_red, m_green, m_blue, m_yellow, m_white,
m_black } MyColors;
	MyColors mc;
	mc = m_green;
	c = mc;
	
	The point is that, while SV allows objects of an enum type to
participate in numeric expressions, it does not allow direct assignment
of an numeric value to an object of an enum type. Strong typing enforces
this kind of type checking to eliminate the possibility of illegal
values being assigned to the object.  What about if I place the same
declaration of an enumeration in 2 different packages?  They are
distinct types.
	
	package p1;
	typedef enum { red, green, blue, yellow, white, black } Colors;
	endpackage
	
	package p2;
	typedef enum { red, green, blue, yellow, white, black } Colors;
	endpackage
	...
	p1::Colors foo;
	p2::Colors bar;
	foo = red;
	bar = foo; //Illegal
	
	What I can do in SV, because the enumeration is an integral type
and cast compatible with other integral types, is explicitly cast an
integral expression to be of a specific enumeration type.  As the
author, I must write the cast expression;there is no automatic casting
inferred.  SV does understand how to do such a cast.  So:
	typedef enum { red, green, blue, yellow, white, black } Colors;
	Colors c;
	c = green;
	c = Colors'(1); // valid explicit cast
	
	I used assignment statements and a very simple strong type to
illustrate SV strong typing rules.  It applies to arguments and actual
connections to ports and parameters in SV as well.  If the types are not
assignment compatible, you cannot make the connection.  What I
illustrated with the enumeration data type examples where assignments
were illegal are types that are not assignment compatible, though cast
compatible.
	
	A key point in the discussion of the requirements for strong
typing is that you should not be allowed to break this kind of strong
typing in SV because you are using mixed language and making connection
to VHDL strongly typed objects. I need to frame the rules for VHDL
enumerated types next to complete the argument.
	
	VHDL enumerated types are strong types(as are all its types). An
enumeration type, like an integer type, is a scalar discrete type which
implies that each value of such a type has a position number that is an
integer value. It is defined by a set of identifiers or character
literals, each of which must be distinct.  The position number of the
first identifier is 0 and each subsequent one has the value 1 more that
its predecessor.  So, in contrast to SV, the encoding of enumeration can
only be a fixed, 0 based encoding, the same as the default encoding in
SV.  Some examples are:
	
	type BIT is ('0','1');
	variable foo : BIT;
	type Colors is (red, green, blue, yellow, white, black);
	variable shade : Colors;
	
	VHDL does not allow type casting, but does support type
conversions between closely related types, but an enumeration type is
not closely related to any other type.  It is possible to take an
integer value and, using an attribute of the type ( which you may
consider a pre-defined function ) convert the integer to a value of the
enumeration type.  Using the variable shade from above:
	
	shade := green;
	shade := Colors'VAL(1);
	
	I may also write a similar example as I did with SV using the
same type declaration in two different VHDL packages.  The result is the
same.  They are 2 distinct and unrelated types. 
	
	I'll note a couple of differences between SV and VHDL enums.
First, there are enumerations in SV for which no equivalent VHDL
enumerations can be constructed, namely those enumerations with
non-default encoding.  Secondly, VHDL supports a stricter model of
strong typing for enumerations.  Type casting in SV will allow you to
assign a value to an enumeration type that is illegal for the type.  It
is not possible in VHDL to make that mistake. The VAL attribute will
perform a range check and report an error for a value that does not
correspond to a legal position number for the enumeration. 
	
	Strong Typing for Mixed Language
	
	Now we can get back to the questions, using the enumerated type
as example.  Both SV and VHDL expect you to declare objects of the same
enumerated type to be free to connect them across hierarchy.  If I have
an SV type declared like this:
	
	typedef enum { red, green, blue, yellow, white, black } Colors;
	
	It is clear to me that this is equivalent to a VHDL type
declared like this:
	
	type Colors is (red, green, blue, yellow, white, black);
	
	But, if these are separate declarations, made in each language
in some declarative region, they are also distinct, separate types. If I
am cavalier about  language rules and simply say that the shape of the
types is enough to call them compatible across languages, then mixed
language allows you to violate either languages rules.  I can connect an
object of one type in SV to an object of any of an arbitrary number of
distinct types in VHDL that have the same shape.  I can then connect
such a VHDL object to another SV object of any of an arbitrary number of
distinct types in SV.  I have used hierarchy to break SV strong typing
rules.  The argument cuts both ways and I can break VHDL rules as well.
This is just wrong and there is no justification for it. Not to belabor
the point, but I don't need to pass objects through ports across a
language boundary if I have hierarchical references that cross such a
boundary.  
	
	It is reasonable to state that we wish to use a single type, the
"same" type in both languages. This is a type that can be shared across
SV and VHDL. How could that be described?  Well, we could define some
new canonical form for the shared type that both language would parse
and whose semantic meaning would be equivalent to the native enumerated
type, but that is a poor solution.  We can say that we may write the
enumeration in either language and define the semantic rules such that
there is a clear and unambiguous equivalent type in the other language.
That is, there is a conformal map, 1 to 1,  between the types.
	
	Now, there remain issues of where is the type declared and how
does one reference the type across the languages.  Important issues, but
they are orthogonal to the discussion of this requirement.  In the
writeup of the requirement, I mentioned shared packages as a way to
support shared types.  Packages are a design units that will be
reference-able across languages, as a consequence of the same naming and
referencing rules we want to have for instantiations.  Packages also are
designed as mechanisms to organize and share declarations.  That is the
purpose they have in both languages, right?  A shared package is a very
transparent, user friendly way to have shared types and preserve strong
typing.   We also don't have to change either language to define such
semantics.
	
	There are other ways.  Here is one I don't like: hierarchical
references to a type across languages. This is severely restricted in SV
(for good reason) as it is and there is no mechanism in VHDL to do this,
so we would have to change VHDL.  What a high bar and long lead time.
If you think about the fundamental language design issues...this would
be a disaster.
	
	Here's another thought. I am not fundamentally opposed to also
having some other way outside of the language for tools to create a
mapping between type definitions in SV and VHDL that says "these types
are 'the same'".  I do believe it requires a lot more consideration of
what can go wrong with the declarative approach, what kind of checking
one might require to be enforced, and what declarations will be
considered erroneous.  "Erroneous" here is the precise term that means
"in error, but not required to be detectable and may lead to
unpredictable or disastrous results".  I also think that any approach
still has to conform to the strong typing requirement and can't be used
to circumvent it.
	
	Applying the Argument to Other Types
	
	It's not difficult to look at the SV struct and the VHDL record
and see how some structs and records are semantically equivalent. They
must have the same ordered set of members, each of which must be of a
type that is defined to be equivalent across the languages.  The
generality we desire starts first with a definition of what built-in and
user-defined scalar types have a semantically equivalent type in the
other language.  For composite user-defined types, which of those are
structurally equivalent mechanisms and what the requirements on its
members must be to arrive at a semantically equivalent type to one
defined in the other language.  Where we do this, strong typing rules
can easily be preserved.
	
	There will be types in one language which have no semantically
equivalent type in the other language.  If there are compelling use
cases in which we feel we must deal with being able to connect objects
of such a type to an object in another language with some "similar"
type, let's see what they are.  My belief is that most of those kind of
cases will be connections that cannot be transparently made.  There will
be information loss, there will operational inconsistency, and the
ability to ruin the conceptual integrity of those objects.  That should
not be standardized and does not need to be.  In my view, it is the user
who must write the conversion to define how the loss of information or
synthesis/initialization of information will be done in user-defined
conversion functions.
	
	What about user-defined classes and mixed language
interoperability?  SV and SC have classes, but VHDL does not.  It is
conceivable that semantic rules can be defined for some user-defined
classes such that an equivalent class in the other language may be
derived, but that may prove to be a difficult problem. If one cannot do
that, the only other possibility is for the user to write conversions or
the equivalent type themselves.  The principal of protecting the
semantics of strong typing are not in conflict with this.
	
	
	To be complete, there are 2 other aspects. First, let's consider
the fact that there are a number of cases of weak types that we must
deal with. These are well-known built-in or standard types that all
tools support.  We must define equivalence between these types that can
be supported automatically.  A vector of wires and a std_logic vector
type both represent the same set of bits in hardware and RTL connections
between them are required.  Defining how well known types across
languages relate to each other is an essential part of our
specification.
	
	Lastly, there is the idea of an opaque or abstract type that
represents the type of object from another language that is not
representable.  It can allow an object of that type to passed through
design hierarchy from language A through language B and back to language
A transparently.  It requires changing language B, i.e., SV, VHDL, and
(possibly) SC to allow this.  It is high bar, longer lead time item and
...so far...the only one we are entertaining.   
	
	Summary
	
	I think what Michael acknowledged and emphasized about Bob's
concerns is the need for conversion functions in the difficult cases.
If we do a solid job of defining where semantic equivalence exists
betweens scalar types and composite types and where it does not, we will
be able to address all the type connections that can be correctly and
automatically connected.  In both languages, one can always write
user-defined functions that take an object of one type and convert to a
value of another type.  That takes us another solid step.  What cannot
be done is to write a function in language A that can return an object
of a type that is not representable in language A.  I can't take a
record in VHDL and write a VHDL function to return a class in SV, can I?
Anyone expect that we have to solve such a problem?  Note, I can do the
reverse, namely take a class in SV and write an SV function to return a
struct.  If that struct is a shared type then I can connect to an object
of a record type in VHDL where the struct and record type are...the same
type!  Here what I have done is kept the loss of information in the
domain of the owner of the class, SV.  I can also pass a record back and
within SV, use it to initialize an object of a class type.
	
	I hope you can see that many of the hard problems have to be
owned by the user and can be designed using the features of the existing
languages.  I trust that we will come to wish for some features to be
added to other languages to make better interoperability possible and we
can advocate for them. I, for one, would like to see us get a solid
initial foundation for interoperability.  We certainly don't have to
solve all the hard use cases in the first revision of the spec.
	
	Regards, John
	
	-----------
	Bob Shur wrote: 

		At last Wednesday's meeting I expressed confusion about
the strong/weak typing proposal. I think most of my unease comes from
not understanding the context of the discussion. Possibly the rest of
this message is based on a misunderstanding of what was being suggested.
If so, I apologize.

		

		If there was a proposal on the table, I wasn't clear on
what it was.

		

		If the idea was to define strong/weak typing, I have no
objection.

		

		I heard the idea that we should be careful to define
things such that a if a language enforces strong typing then it should
not be possible to circumvent that by mixing languages. This seems
reasonable. I don't know when it applies, though. Some examples of where
we're in danger of having this problem would help me.

		 

		I'm also not clear on the definition of strong typing.
For example, when you call a C++ function, you have to pass actual
arguments that are convertible to the formal arguments. You can pass an
A to a function(B) as long there's there an A::operator B or B(A)
constructor. I'm not sure whether you're calling that strong typing or
not. 

		

		The example of an SC interface was given in  John
Shields' message of April 26, in which he said:

		

		For example, SC certainly has strong requirements for
matching class types at its interface.  Defining, generating, and using
equivalent derived declarations to do type checking between SV or VHDL
and SC should be part of the specification and implementation.

		

		I'm not sure what was meant by "equivalent derived
declarations" here. My view is that where SC needs an object that
implements some interface, the object has to be, in fact, a C++ object
that implements the interface. There's not much choice, since the C++
code that makes calls to that interface is compiled by an off-the-shelf
C++ compiler and assumes that the object it's calling is  a C++ object
that implements the interface. This object may not be the same one that
user mentions-for example, if the user tries to bind a verilog class
instance to a SystemC port we might create a behind-the-scenes C++
object that we bind to the SystemC port, with the behind-the-scenes
object somehow linked to the Verilog class instance. I see no apriori
reason why the Verilog object and the behind-the-scenes C++ object have
to be the "same" type-only that operations on one can be translated to
operations on the other.

		

		I'm happy with the idea of coming up with a way to
enforce, or create by construction, "same" types in multiple languages.
But I expect we will also need to come up with a way to populate a
library with converters between types in different languages. In that
case, the "same" types would become a special case in which the
converters were automatable so the user would not have to think about
them.

		

		If what I've attempted to express here does not conflict
with what I was asked to vote on last Wednesday, then I'm happy to
change my vote from "need more time" to "yes".


		-- 
		This message has been scanned for viruses and 
		dangerous content by MailScanner
<http://www.mailscanner.info/> , and is 
		believed to be clean. 


	-- 
	This message has been scanned for viruses and 
	dangerous content by MailScanner <http://www.mailscanner.info/>
, and is 
	believed to be clean. 


-- 
This message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.
Received on Tue Jun 26 19:09:44 2007

This archive was generated by hypermail 2.1.8 : Tue Jun 26 2007 - 19:09:46 PDT