New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[RFC] What does it mean to be a Bundle? #765
Comments
I think the goal of Option 2 is more elegant and intuitive (visually obvious what is and isn't a Bundle field, compared to using a Scala keyword to double as "this is a Bundle field" and a Java access modifier to double as "no, I didn't really mean that to be a Bundle field"), but YMMV. One issue with Option 2 is implementation, it would require reflection-based checking. Java reflection can only get constructor argument types, but not names. So in the case where you have a Data subtype in the argument list, the Bundle class must be Scala reflect-able. The only case I know of where this fails is for classes within an anonymous outer class, where reflection barfs with a CyclicReference exception. This is probably a Scala bug. (otherwise, most of the cases where autoclonetype fails isn't an issue here: it doesn't need the outer instance that autoclonetype does). Reflection has also been slightly wobbly in general, such as the case of Class.forName in the previous version of Chisel's user-code-line locator for errors interacting badly with constructor invocations in clonetype. But that's mostly out of our control, probably a Java/Scala bug. Aliasing is another issue with directly using constructor Data arguments. For example, one case that would appear correct is class MyUselessBundle(val thisIsAField: Data) extends Bundle
class MyBundle(private val dataType: Data) extends Bundle {
val field1 = new MyUselessBundle(dataType)
val field2 = new MyUselessBundle(dataType)
}
In general, proper style should probably recommend that leaf-level instantiations of a type be wrapped in tl;dr: I like option 2 style-wise and option 1 has a critical issue handling aliasing, but there are some implementation risks with option 2 that I think shouldn't affect the majority of use cases. In both cases Chisel shouldn't fail silently and give you wrong RTL, but giving helpful error messages in all cases for either option may not be straightforward. |
Resolution from today's meeting: Immediate plan for 3.1
Future cleaner APIsFor 3.1.1 or 3.2, we will be introducing a new, optional Bundle
Suggestions are welcome in designing a better 3.1.1/3.2 API. This is not yet set in stone and is not expected to produce compatibility issues with old code. |
The standard pattern for using Chisel Data objects as generator parameters in Bundles is to pass them as a constructor argument like so:
In the modern world of autoclonetype; however, you are encouraged to make constructor arguments
vals
so that reflection can find them. If you makegen
aval
:Whoops, you've accidentally added a new element to your Bundle called
gen
! This is due to the fact that the elements of a Bundle are defined (by implementation) to be the public vals of typeData
orSome[Data]
.Instead, you should use a private val:
While a little verbose this allows autoclonetype to automatically generate clonetype so everyone is happy.
This led to a discussion on what the fundamental definition of a Bundle is/should be. As far as I can tell there are two possibilities:
1. Bundle Elements are the public vals of the Scala class (the status quo)
As far as I know, this hasn't been much a point of confusion for new users; however, with autoclonetype encouraging people to make their constructor parameters
vals
it most certainly could become one. To make this better, I think there are a couple of things we should do:chisel3.core.Binding$MixedDirectionAggregateException
caused by a val constructor parameter of typeData
orSome[Data]
, inform the user that it counts as an element and link to the wiki page.cloneType
on them. This is needed since these constructor arguments are not just generator parameters, they belong to the Bundle so we need fresh objects.There is one case where I'm not sure if we'll be able to [easily] provide a decent error message though. For a Bundle with no directions at all, you can end up with a
firrtl.passes.CheckInitialization$RefNotInitializedException
if you have a val constructor parameter of typeData
that you didn't intend to be an element of the Bundle.2. Bundle Elements should be vals in the body of a Bundle
It is a keen observation that there are very few examples of people using val constructor parameters to create fields of Bundles (I only know of one h/t @grebe). Perhaps it is better to redefine Bundles such that constructor arguments of type
Data
orSome[Data]
are not elements, rather they are just constructor parameters.This has the nice property of encouraging separation of generator parameters and elements of the Bundle, and encourages people to express Bundles in a way similar to a C-struct. Misuse (eg. connecting to a val that is a constructor parameter) is also very easy to detect and provide a specific error message. As far as I know there aren't any obvious cases we can't catch like the one above. That being said this kind of a change would require carefully considering its implications on inheritance (especially overriding elements that may be a constructor parameters for a parent class)
I think there are other benefits as well, but I'm blanking so maybe @ducky64 can comment with some thoughts.
In any case, I think we should stuck with 1. but after some discussion in a meeting we thought we ought to ask the community to see what users think!
Type of issue
What is the use case for changing the behavior?
See 2. above.
Impact
Development Phase
The text was updated successfully, but these errors were encountered: