Question: Is there a way to instantiate an extern like in the example code without giving `_` as a type parameter?
@mbudiu-vmw @jnfoster @ChrisDodd My apologies for pinging you directly on this, but I suspect you are the ones most likely to know the relevant parts of the P4_16 language spec and p4c implementation related to this. I am marking this as a question because my guess is that the answer for at least some time to come is "that is probably the least hacky way to do what you want for now", and if so, I will simply close this as an answered question issue.
See the definition of the extern object named ExactMatchValueLookupTable in the attached program, and the instantiation of an instance of it named lut1.
If P4_16 had a fancier type system (or maybe it does and I do not know how to express it), I would like to only have type parameters K and V, and then the second parameter of this constructor signature:
ExactMatchValueLookupTable(int size, E const_entries, V default_value);
would be the type "a list of (K,V) pairs", instead of E.
As it is written now, I can compile this with the latest open source p4c, but the only way I have found to avoid syntax errors so far is to declare the extern object with the type parameter E, and then provide the type parameter _ for E when I instantiate lut1.
I am personally OK with doing this, but I agree it feels a little like a workaround. Dan Talayco was curious if we can do better, either with today's language specification, or with any enhancements that we think might be coming to the P4_16 specification some time in the next few years.
One view of the problem is that P4_16 does not have syntax for writing the list type. (The IR node Type_List is used internally in the compiler, but there is no way to get the parser to produce that type from the text of a program -- it's only introduced by the compiler during type checking.)
The language specification says that list expressions have tuple types. So in situations where your code only deals with a single, concrete list (to be clear -- not your situation!), you know the length of the list and can write down a type for it. For example, if you knew the entries would always be a list of length 3, you could write:
tuple<tuple<K, V>, tuple<K, V>, tuple<K, V>>
for its type.
When you write the _ in the declaration of your extern, you're allowing the compiler to infer any type, including all tuple types comprising Ks and Vs (but also all other types -- so this is dangerous!)
A proposed solution would be to add list<T> as a type. Then you could declare the extern as
extern ExactMatchValueLookupTable<K, V, E> {
...
ExactMatchValueLookupTable(int size, list<tuple<K,V>> const_entries, V default_value);
}
One minor detail is that we'd probably want to change the type computed for list expressions. Right now a list gives a "flat" tuple type:
tuple<bit<8>, bit<8>, bit<8>> t = { 0, 1, 2};
but really we would want the type to reflect the structure of the list. So a value of type
list<E>
should be coerceable to
tuple<E, list<E>>
unless it is empty, in which case it should be coerceable to:
tuple<>
So I'd argue the code above should look more like this:
tuple<bit<8>, list<bit<8>>> t = { 0, 1, 2};
or even
tuple<bit<8>, tuple<bit<8>, tuple<bit<8>, tuple<>>>> t = { 0, 1, 2 };
Yes, we do not have list types, so there is no way to declare an object whose value is a list of unknown size of identically-typed values. Even the internal list type has a fixed length, it does not unify with an arbitrary-length list. A question is whether we could design the syntax and type system to be flexible enough to allow the standard P4 tables to be declared as extern objects by an architecture. You are moving in that direction.
In the interest of tidying up the set of active issues on the P4 specification repository, I'm marking this as "stalled" and closing it. Of course, we can always re-open it in the future if there is interest in resurrecting it.