_This issue was originally filed by zhygrr...@gmail.com_
It would be nice if we can introduce classes local to a given enclosing class.
class Outer {
void doSomething() {
var inner = new Inner();
}
class _Inner {
}
}
This allows define class that is invisible outside of the Outer class scope.
I understand that this feature requires more investigation. As for me it has a limited power if a class is not the first class object (or a class could be a class member like fields or methods).
_Removed Type-Defect label._
_Added Type-Enhancement, Area-Language, Triaged labels._
The idea of nested classes is very familiar to us (see. e.g., Beta, Newspeak). To avoid any misunderstandings, I should make it clear that we would NOT do this the way it was done in the Java programming language. Whether this will happen in Dart is an open question.
_Set owner to @gbracha._
_Added this to the Later milestone._
_Added Accepted label._
_This comment was originally written by astimo...@gmail.com_
I would be very happy if inner classes were only a means of taking advantage of lexical scoping for the organization of classes by name.
class Foo
{
Bar bar;
Baz baz;
Foo()
{
bar = new Bar();
baz = new Baz();
}
class Bar
{
}
class _Baz
{
}
}
new Foo.Bar(); // acceptable
new Foo._Baz(); // unacceptable
By "only a means of taking advantage of lexical scope" I mean to exclude the java behaviour of creating a runtime reference to the outer class unless the inner class is declared static. For that case the program can explicitly provide the outer class to the inner class.
Thus the following will not work:
class Foo
{
Bar bar;
Foo()
{
bar = new Bar();
bar.speak();
}
void hello()
{
print("hello");
}
class Bar()
{
void speak()
{
hello();
}
}
}
But this will work:
class Foo
{
Bar bar;
Foo()
{
bar = new Bar(this);
bar.speak();
}
void hello()
{
print("hello");
}
class Bar
{
final Foo foo;
Bar(Foo foo)
{
this.foo = foo;
}
void speak()
{
foo.hello();
}
}
}
_Removed this from the Later milestone._
_Added Oldschool-Milestone-Later label._
_Removed Oldschool-Milestone-Later label._
_This comment was originally written by PortalProgra...@gmail.com_
Any updates on this issue?
Not really.
It quite often the case that an enum has a very strong relation to a class - because of this missing feature I can't write "inner-enums" - annoying.
You can make the enum library-private. Not the same of course, but quite close.
Thanks - I know. But this:
class MyCoolClass {
enum Props { HOT, NEW, COOL }
...
}
...
switch(props) {
case MyCoolClass.Props.HOT:
break;
...
}
is what I want.
I know - in Java its a bit problematic if the inner class is not static - C++ does it right. Dart should have a similar thing.
I got it that you want that. The question is if it's worth to complicate the language for that.
What's the advantage of having it inside the class instead of outside, that makes it worth to make the language more complex?
I'm not arguing against it. Just curious what you think would be the big advantage.
I think it's just for the communications/maintainability scalability of a systems engineering language.
Referring to say network.get(..., cache: Network.CachingStrategy.A) (which is a public API) is cleaner than having a NetworkCachingStrategy global class/enum lying around all the time.
I would agree. One thing I would say as well, is that I think very rarely should dart files define multiple classes.
Usually when I do see it I don't disagree with the structuring of the code, but I do find it hard to use the resulting api.
import 'something.dart';
...
var something = new Something();
something.use(new UsedBySomething());
new FinalizesSomethings.finalize(something);
There's no easy autocomplete for "what does the something package expose again?" Its also hard when reusing this code elsewhere, to figure out which import brings in which classes.
You could do prefixed imports, but now you've either got the tedious something.Something or you've got the cryptic smt.Something. Oh and you can no longer use smt or something as variables when you do this.
I think it would be a nice improvement if we only ever defined one class in a dart file, and relied on inner classes where they are so related that they deserve to be in the same file.
var something = new Something();
something.use(new Something.UsesThis());
new Something.Finalizer(something)
You may also not be surprised to hear that I think this is less of an issue when the classes are named CommonFoo rather than FooCommon since that's basically what my new code is, just with an extra dot. But its pretty common that these things don't match up perfectly. And even then, you never know when "SomethingFinalizer" is in "something.dart" or "something_finalizer.dart".
Obviously there's a conflict here with the syntax, as Finalizer could be the name of a constructor on Something rather than a class on Something. Probably would be a ton of work to solve.
Overall my opinion is that it would be a small but appreciable win for dart.
I should make it clear that we would NOT do this the way it was done in the Java programming language.
@gbracha In what way would you do it differently in Dart?
(PS: Gilad is not in the Dart team now, he went on to pursue new adventures elsewhere.)
That said, I think this is the right place to gather arguments for or against adding class nesting (static or otherwise) to Dart, but also that there is relatively modest support for the idea at this point.
@eernstg Do you have any idea what Gilad meant about doing it differently than Java?
@eernstg Maybe like Kotlin - where an inner class is always static (Doesn't have a reference to it's outer class) except it is marked with the "inner" keyword
https://kotlinlang.org/docs/reference/nested-classes.html
Gilad's Newspeak includes nested classes, and they are related to the general nesting in BETA and gbeta (of patterns, which is a general concept that includes classes and a lot of other things in one language mechanism), and those languages all make nested classes members in a way that resembles methods (in particular, a nested class is subject to late binding). That's a rather powerful concept, aka virtual classes or virtual patterns, and — who knows — that might have been on his mind when he said ''we would NOT do this [like in Java]".
On the other hand, static inner classes are even less powerful than Java inner classes, they provide nothing else than scoping (that is, certain things will have shorter names in some contexts). So I doubt it was that.
In any case, virtual classes in Dart would be such a huge generalization (of many things, including the type system), so we won't get that in any reasonable amount of time. ;-)
Yea I was trying to build a JSON to object mapping library but got stuck in this issue.
I want Enums as sub-types of classes for more code clarity.
In java I always enclose the http request like this.
doGet(String requestUrl, DioRequestCallback callback) async {
Response getResponse = await dioInstance.get(requestUrl);
print(getResponse.statusCode);
}
If the inner class not work,I might write the request in many places.And I cant custom to handle server response code in one place.
In java I always enclose the http request like this.
doGet(String requestUrl, DioRequestCallback callback) async { Response getResponse = await dioInstance.get(requestUrl); print(getResponse.statusCode); }
If the inner class not work,I might write the request in many places.And I cant custom to handle server response code in one place.
I find a way to resolve that.
doGet(
{String requestUrl,
successCallback(int statusCode),
errorCallback(int statusCode)}) async {
Response getResponse = await dioInstance.get(requestUrl);
print(getResponse.statusCode);
}
use function as param.
Without it, there is no way for nesting necessary listeners inside the appropriate class and nesting Builder class in the builder design pattern. Any updates?
I want to use builder design pattern.Nested classes is necessary.
Since everybody knows about it, I don't want to talk any more!
Come on, it's been 8 years, goddamn
@egorikem wrote:
Come on, it's been 8 years, goddamn
I can understand that this is a serious source of impatience.
However, this feature never made it to the top of the list. It is my impression that the main reason is that it causes Dart software to become more complex, especially syntactically (because it could push Dart software in the direction of having a lot of huge, nested {...} blocks). Conversely, the case for having it has not been made in a sufficiently compelling manner.
In particular, it would be convenient that the names of certain entities can be abbreviated (e.g., calling a static method named m from inside a class C could use m() whereas any location outside C would have to use C.m()), so that could be an argument in favor of static nested classes or dynamic nested classes (like Java's inner classes). But static nested classes can be rewritten to top-level classes by using the class prefix C. as needed. Similarly, dynamic nested classes can be rewritten to top-level classes where a certain member, let's call it outer, is a reference to the (emulated) enclosing instance of C.
Access to an emulated nested class would be different (for clients using them as type annotations, or creating new instances of them). But having rewritten a given nested class to a top-level class, it is certainly possible to use that top-level class as a type annotation, or to create instances of it (passing a reference to the emulated enclosing object in a constructor), and I don't see how this would not be a complete and faithful emulation.
@mpowloka wrote:
Without it, there is no way for nesting necessary listeners
inside the appropriate class and nesting Builder class in
the builder design pattern
Maybe you could give an example, and then we could explore approaches where the nesting is emulated and see how inconvenient it is?
At least would be nice to have enum inside classes. Is very intuitive to have enums related in the same place.
The idea of nested classes is very familiar to us (see. e.g., Beta, Newspeak). To avoid any misunderstandings, I should make it clear that we would NOT do this the way it was done in the Java programming language. Whether this will happen in Dart is an open question.
_Set owner to @gbracha._
_Added this to the Later milestone._
_Added Accepted label._
I don't understand, why you made this point as something Java related? Do you really understand context of having nested classes?
Let's add nested classes in way it works in Python, C++, C#, Scala. As simple as that. And should nothing to do with language here. Having nested classes makes you object looks clear and transparent, when it comes to have composition of nested private Objects.
@eernstg
Maybe you could give an example, and then we could explore approaches where the nesting is
emulated and see how inconvenient it is?
Sure. I think by that statement @mpowloka meant having inner object to hide visibility inside class.
OnTapListener is very intuitive to have inside GeastureController. Furthermore if all the handling performs inside controller only. Builder classes for of it is objects. When you cannot directly create something with simply Abs and instead should use Abs.Builder class to instantiate an Object.AdvancedMap and inner node object should nothing to do outside. And AdvancedMap it's composition of inner objects AdvancedMap.Node. And I can continue this list. Again. It's not about, how we can accomplish this with Dart. It's question about transparency, dependency tree, clarity of a Classes.
@eernstg
However, this feature never made it to the top of the list. It is my impression that the main reason is that it causes Dart software to become more complex.
Why we don't have this issue for hounders of other languages. But for your cases we will? Because of what? Implementation? But in this way we can criticize everything. I never seen language issue caused by inner Classes so far. And even your example is about implementation. And should nothing to do with out points above.
@GensaGames wrote:
hide visibility inside class
I see a complexity based argument here: It makes sense for OnTapListener to be nested inside GestureController, because a reader of the code won't have to worry about understanding OnTapListener unless GestureController is of interest. This is conceptual and I think this is a very important area. However, I also think that there's a delicate balance here: It may be easier to understand a library with 20 classes if we only have 5 classes at the top level, and the rest are nested in one these top level classes. But if that means that a given class is a 500 line construct rather than a 100 line construct then maybe the net effect isn't obviously a readability improvement, especially if we have class-in-class-in-class and so on, and if scope rules have a bunch of new exceptions (because a static nested class cannot access declarations in enclosing scopes if they are instance members or type variables).
We also have a namespace management argument: A nested class Builder can have a simple name because it's denoted as Abs.Builder and hence it doesn't clash with other things named Builder, and similarly for AdvancedMap.Node. We could actually get this effect simply by allowing top level declarations to have names of the form <identifier> '.' <identifier>.
The third argument that we've had on the table earlier is "access to a nested entity is more concise when it is in scope"; so AdvancedMap.Node could be denoted by Node inside AdvancedMap, which is convenient and readable in that context.
So we certainly have arguments in favor of nested declarations, along with some counter-arguments, but this doesn't really illustrate any technical reasons for why the nested definitions would enable us to simplify a concrete example.
Implementation?
The implementation is not an issue. Nested classes in Java (static and inner) were implemented many years ago as a relatively straightforward program transformation, and we can certainly use the same techniques in Dart. The question is whether it's a good feature to have for developers who need to create and maintain high quality software in Dart, and for me the picture looks somewhat mixed.
@eernstg
(static and inner) were implemented many years ago as a relatively straightforward program transformation, and we can certainly use the same techniques in Dart.
I don't understand why Java really should have context here. We can talk about nested classes inside every other language (React, Python, TS, basically most of them). And talking aside our subjective opinions above - there is no issue at all using them. For all other cases.
@eernstg ,
Maybe we can choose democratic way. Aside of your opinions we can create poll, where all contributors will vote, based on their experience. And finally resolve this question?
We can't promise a specific procedure, but an issue like this one with a lot of :+1:'s is taken seriously. At the same time, language changes do take time (e.g., dart-lang/sdk#22 is the big thing we're doing right now).
this is the exact problem we faced as android developers back when i was using kotlin and android-studio instead of flutter. at first android team was working hard but then they got lazy and stuff which lead them to hack the problems instead of solving them. which lead to the creation of abominations like Android Support library which was a total hack. I guess i just have a fear of the same thing happening to flutter
Any progress?
Everybody is still fully occupied working on non-nullable types (implementing it, porting the standard libraries, and lots of other stuff).
I just want to add another case where nested classes are useful. Constants that are subdivided into categories.
For example:
int statusCode = HttpStatusCodes.ClientError.forbidden;
Will this ever happen? I have a case where I have a TranslationLocalizations class and I would like to group my translation string inside this class by categories. Inner classes would help with this a lot
TranslationLocalizations.of(context).HomeScreen.title
Dart is already in v2.8 and still cannot do any nested classes. Today, this feature is kind of basic as doing class extension...
Can you guys at least move it at the top of your list!
If I'm not too late to the party, I have an approach(workaround) for inner/nested class:
class AppConstants {
static const _Style Style = const _Style();
static const _URL Url = const _URL();
}
class _Style {
const _Style();
final EdgeInsetsGeometry buttonPadding = const EdgeInsets.all(10.0);
}
class _URL {
const _URL();
final String game = 'https://example.com';
}
main() {
var myStyleToUse = AppConstants.Style.buttonPadding;
}
I would really like the know the downsides of this though, if anyone can figure out. :beers:
I like your idea @arnold-parge. There're 2 downsides I can see at the moment:
lowerCamelCase. You can find the convention here.Happy coding. 🍻
@leafpetersen @munificent @lrhn – this should be a language issue?
@kevmoo I've been refraining from moving all language issues in the SDK repository into the language repository. Obviously they belong there, but if there is no recent interest in the issue, then it might as well be left where it is.
@kevmoo I've been refraining from moving all language issues in the SDK repository into the language repository. Obviously they belong there, but if there is no recent interest in the issue, then it might as well be left where it is.
Can we expect this in Dart in the long term?
There are no current priorities that make us work on nested classes. The problems it solves are just not the most urgent problems for us to solve right now.
If priorities change, anything can happen.
... In the very long run everything is possible, and nothing is probable ...
I can't see even one case where this is useful.
Most helpful comment
It quite often the case that an enum has a very strong relation to a class - because of this missing feature I can't write "inner-enums" - annoying.