Replies: 16 comments
-
It really seems like there are multiple intertwingled proposals here:
I'd propose using a compound keyword (like yield return) leveraging the existing "object" keyword/type. Say "object class" for inner classes, and "object instance" for instantiating an anonymous inner class on the spot. So for a java-style inner class, use public class Foo() {
public void DoFoo(){
Console.WriteLine("Foo");
}
public object class Bar {
public void DoBar() {
DoFoo(); //accessing parent object's members.
}
}
}
public static class Demo() {
public static void Demo() {
var myFoo = new Foo();
var myBar = new myFoo.Bar();
myBar.DoBar(); //prints "Foo"
}
} For an inner object with anonymous class as a member public class Foo() {
public void DoFoo(){
Console.WriteLine("Foo");
}
public object instance Bar {
public void DoBar() {
DoFoo(); //accessing parent object's members.
}
}
}
public static class Demo() {
public void Demo(){
var myFoo = new Foo();
myFoo.Bar.DoBar(); //prints "Foo"
}
} For a java-style anonymous inner object made in a method body. public static class Program {
public static void Main(string[] args) {
var message = "Hello!";
var myObj = object instance : IDisposable {
void SayHello() => Console.WriteLine(message);
public void Dispose { /* do nothing */ }
}
foo.SayHello();
foo.Dispose();
}
} |
Beta Was this translation helpful? Give feedback.
-
I would love both of the features @Pxtl outlined. |
Beta Was this translation helpful? Give feedback.
-
I don't care for the syntax suggested. I'd argue that C# already has the syntax necessary to accomplish both local and anonymous types: public void FooLocal() {
class Bar : IDisposable { // local class
public void Dispose() => Console.WriteLine("disposed!");
}
var bar = new Bar();
bar.Dispose();
}
public void FooAnonymous() {
var bar = new IDisposable { // anonymous type implementing an interface
public void Dispose() => Console.WriteLine("disposed!");
};
bar.Dispose();
} Although the team had already weighed in on anonymous types implementing interfaces. |
Beta Was this translation helpful? Give feedback.
-
@HaloFour Agree about the syntax, but desperately want both features. That won't change. |
Beta Was this translation helpful? Give feedback.
-
The reason I suggest the "object instance" syntax is just to avoid keyword collisions. Compound keywords are ugly, but they preserve backwards compatibility with programs that may already use the new "instance" keyword for variable-names and class-names, and the "object" keyword may not work out because that's already a type name. For example, just using the "new" keyword and an interface makes it hard to differentiate between the class body and a constructor body. For example: public void FooAnonymous() {
var bar = new BaseClass {
}
} Am I constructing an instance of BaseClass or am I subclassing BaseClass and constructing an instance of that? Is the curly brace a class definition or a constructor initializer? This is ambiguous. Also, let's say I'm extending BaseClass to implement a new interface - where does the colon go? public IMyNewInterface {
public void DoInterfaceStuff();
}
public class OwnerClass {
public void FooAnonymous() {
var bar = new BaseClass : IMyNewInterface {
public void DoInterfaceStuff() { this._MyProtectedMember.DoStuff(); }
}
}
} That's a bit weird since BaseClass does not implement IMyNewInterface, rather our new class derives from BaseClass and implements IMyNewInterface. That's why I suggest a new keyword for "instance of a new anonymous class whose definition follows". My preferred keyword would be "instance" but that's not a reserved word so it may already be in use in ways that would not be backwards compatible, so I propose "object instance". Hence, my suggested syntax applied to example above: public IMyNewInterface {
void DoInterfaceStuff();
}
public class OwnerClass {
public void FooAnonymous() {
var bar = new object instance : BaseClass, IMyNewInterface {
public void DoInterfaceStuff() { this._MyProtectedMember.DoStuff(); }
}
}
} Maybe a different keyword besides my ugly "object instance" would fit there. I haven't considered all the parsing implications - maybe class, even - "new class" isn't a combination of keywords that makes any sense in current C#. That actually may work better because you could also use it for structs - "new struct" for instancing an anonymous struct on the spot that can implement interfaces. I'm less fond of this because it's not creating a class but rather a class and instantiating it. But we can still use the normal constructor notation afterwards. Actually, the more I think about it, the perfectly normal full C# class declaration stuck in the procedural code does the job. This adds extra benefits like being able to use typeof() to create an anonymous class if you need a Type instead of a constructor. The only limitation is that, being anonymous, the class has no way to refer to itself or its constructor. I guess for that case you may need to create a real class. public IMyNewInterface {
void DoInterfaceStuff();
}
public class OwnerClass() {
public void FooAnonymous() {
var bar = new class : BaseClass, IMyNewInterface {
public void DoInterfaceStuff() { this._MyProtectedMember.DoStuff(); }
}(); //parens for constructor arguments.
}
} So you see, everything from the word "class" to the final "}" is a perfectly normal class declaration, only unusual in that it is present within a method. Theoretically we could get into inner class stuff where the anonymous class captures variables from OwnerClass, but we'll ignore that possibility to demonstrate that this code is equivalent to: public IMyNewInterface {
void DoInterfaceStuff();
}
public void BarClass : BaseClass, IMyNewInterface {
public void DoInterfaceStuff() { this._MyProtectedMember.DoStuff(); }
};
public class OwnerClass() {
public void FooAnonymous() {
var bar = new BarClass(); //parens for constructor arguments.
}
} Exact same class declaration, but moved outside of FooAnonymous. That's it. So we can use the exact same normal syntax for classes and structs for anonymous inner classes and then we don't have to sacrifice any features of classes - they can subclass, they can implement interfaces, they can expose fields and methods and properties. All the same stuff. now to demonstrate the other weird application of this. public IMyNewInterface {
void DoInterfaceStuff();
}
public class OwnerClass() {
public void FooAnonymous() {
var barType = typeof(class : BaseClass, IMyNewInterface {
public void DoInterfaceStuff() { this._MyProtectedMember.DoStuff(); }
});
}
} See that? If we separate the concept of The only thing I can't figure is the self-reference component. Classes often need to refer to their own name, even for declaring constructors and destructors or implementing clone operations or whatever. And this doesn't have a name. |
Beta Was this translation helpful? Give feedback.
-
I think this issue should be kept simple and on topic. Nested local types should behave exactly like nested types that are only visible to the local method. Anything else should be a topic for another issue. This means that there should be no lexical scoping or hidden field with a reference to the outer class or new keywords. If you want a reference to anything in the outer scope, it should be passed to the nested local class's constructor and stored as a field explicitly, just as you would have to do with a regular nested class. This is a very useful feature and it will not get implemented if it is not kept simple. |
Beta Was this translation helpful? Give feedback.
-
Seconding simplicity to start. This proposal combined with lightweight record types (#39) is immensely powerful for representing temporary high-arity method-specific intermediate state, where declaring helper types or leveraging tuple types feels too heavy/unwieldy/verbose. The above conversation seems complex. Heavier local types will probably require a lot more thought - what's the threshold between a local record type (POCO) and a larger local type that really should be a unit-testable class-nested helper class? Can I unit-test local types? The examples provided thus far seem like verbose ways of implementing an interface when perhaps the interface really should just be a Func? Perhaps it makes sense to discuss heavier local types another time. |
Beta Was this translation helpful? Give feedback.
-
You wouldn't unit-test a local function. |
Beta Was this translation helpful? Give feedback.
-
Not sure if i missed it. But local types especially local structs make most sense for me if their methods can close over variables of enclosing methods . Pseudo codes: public interface IDropStateHandler {
void drop_state(SomeSharedState cutchainat)
}
public class SomeSharedState {
private SomeSharedState next;
private long sample;
public IEnumerable<SomeSharedState> iterateDrop<DropState>
where Dropstate: struct,IDropStateHandler ( long iteratetillsample ) {
SomeSharedState continuewith = this;
while ( continuewith.next != null ) {
if ( continuewith.sample >= iterattillsample ) {
( new DropState() ).drop_state(continuewith);
yield break;
}
yield return continuewith;
}
( new DropState() ).drop_state(continuewith);
yield break;
}
}
void doiterate something () {
SomeSharedState tail;
SomeSharedState newtail;
long haltatsample;
struct FinalDropper:IDropStateHandler {
public void drop_state(SomeSharedState cutchainat) {
newtail = cutchainat;
}
}
struct IgnoreDrop:IDropStateHandler {
public void drop_state(SomeSharedState cutcahinat) {
}
}
while ( true ) {
magicsample = somemagicupdate();
foreach ( SomeSharedState state in tail.iterate_drop<FinalDropper>(haltatsample) {
}
foreach (SomeSharedState state in tail.iterate_drop<IngoreDrop>(haltatsample) {
}
tail = newtail;
}
} In order to achieve this the closure has to be passed in via delegate parameter which has to be checked if it is null and if replaced by some noop default. The above would hint the backend/jit that form algorithm perspective it would be ok to optimize away the noop closure for the second iterator variant in case would be reasonable. This would be a more sophisticated way to drop breadcrums to the backend compiler/jit. Which is currently already possible for structs having only methods and properties which return constant values like so. Pseudo codes: public interface IGBool {
bool Value{get;}
}
public struct GTrue {
public bool Value{get{return true;}}
}
public struct GFalse {
public bool Value{get{return false;}}
}
void dosomething<BranchSwitch>()
where BranchSwitch:struct,IGBool {
if ( ( new BranchSwitch() ).Value ) {
// do only if switch ist constant true
}
else {
// do if branchswitch is constant false
} What happens here the two struct GTrue and GFalse have beeing structs no ctor and thus no code is emmited for new. Further they do have no fields neither explicit nor implicit as getter returns constant value, thus no context / stack operation either for creating struct. Remains the getter of the property returning a constant. If callsite optimizer of backend decides to inline the call than suddenly branching happens upon constant never chaning value, which may or may not trigger branch optimizer ... but at least backend has got some information that algorithmwhise there would be the possibility to drop the code for either if or else block completely. That does not mean that it will do it under very circumstance but it likely might do it. Yes that is speculating with beeing backend so kind to second in optimization of implementaiton. It definitly requires that programmer first has carefully optimized algorithm and wants to drop information to backend upon the algorithm used and where it would allow to aggressively optimize native code without breaking any thing. |
Beta Was this translation helpful? Give feedback.
-
This would greatly simplify a number of our bespoke DB queries that need a temporary type to avoid performance penalties of using an ORM directly. public ActualResult QueryWithPerformanceConsiderations(int arg0)
{
class DbResults
{
public int Property0 { get; set; }
// ...
}
var results = _context.Database.Query<DbResults>(@"query", new { Parameter = arg0 });
// ... avoids any use of dynamic or dictionaries of objects
} |
Beta Was this translation helpful? Give feedback.
-
Same goes for querying a REST service, where currently you either have to predefine a type 'outside' your method, or resort to dynamic types. |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
This would be really useful in a lot of places where a named tuple becomes clunky and overly verbose, or just unclear, or you need a named type void Method()
{
struct MyType { public uint X, Y; public float K; }
_foo.SomeMethod<MyType>(...);
}``` |
Beta Was this translation helpful? Give feedback.
-
Coming back to it 4 years later, the more I think about it the more I think this should just be an expression. It makes it so much simpler. But there's a problem with expressions returning (1) Allow class Program
{
static void Main(string[] args)
{
var myClass = class {
public MyClass(myString)
=> MyString = myString;
public string HelloWorld()
=> Console.WriteLine(MyString);
}
}
} is actually equivalent to internal class MyClass
{
public MyClass(myString)
=> MyString = myString;
public string HelloWorld()
=> Console.WriteLine(MyString);
}
class Program
{
static void Main(string[] args)
{
var myClass = typeof(MyClass);
}
} Now, the first thing you'll notice is that this is worthless. Instances of So we introduce (2), another new feature: Effectively, the local type above implicitly declares and gives you an instance of this... public class MyClassTypedType : System.Type
{
public MyClass Construct(string myString)
=> new MyClass(myString);
} ...where the given instance corresponds to So instead of The ergonomics wouldn't be perfect, of course, since you wouldn't use But, it would tick all the buttons without messing with namespaces as you introduce new items into the "type" namespace that become awkward. You can write classes anywhere you like, but they're all just expressions that give you a slightly-weird Type subclass object. And that object has a convenient way to access the constructors of the class you wanted, thanks to TypedTypes. So to say "create this local class and give me an instance of it", we just say: class Program
{
static void Main(string[] args)
{
var myInstance = class {
public MyClass(myString)
=> MyString = myString;
public string HelloWorld()
=> Console.WriteLine(MyString);
}.Construct("Hello, World!");
myInstance.HelloWorld();
}
} |
Beta Was this translation helpful? Give feedback.
-
hernot That sounds interesting but some questions remain at least from my side. When these declarations expanded: at compile time, jit-time or run-time? See my examples upon passing hints above about algorithm implemented to jit for probable use in optimization steps. EDIT |
Beta Was this translation helpful? Give feedback.
-
Hopefully, one day this would be implemented. Android .NET developers would be happy to have it. |
Beta Was this translation helpful? Give feedback.
-
@jnm2 commented on Mon Mar 07 2016
Extend the languages to support the declaration of types in block scope.
As per gafter's instructions. This would be a terrific feature for the same reasons as local functions: scoping, keeping together when moving, declaration closer to the usage.
@HaloFour commented on Mon Mar 07 2016
I guess my question here is what kind of "local" types are we discussing? Full-fledged types which just happen to be declared and scoped within a method block? Anonymous implementations of an interface or parent type? All of the above? What are some specific use-cases?
From my experience with Java it seems that anonymous implementations are quite common (not even including functional interfaces). Local classes seem relatively rare by comparison as nested classes seem to be sufficient in isolating code at least from outside consumers.
@jnm2 commented on Mon Mar 07 2016
Full-fledged types which just happen to be declared and scoped within a method block. I think anonymous implementations are another topic which apparently won't happen (bit sad about that).
One use case that I've had in mind is smart tuples, structs that are one step away from anonymous types but that implement an interface or have decision-making ability of their own. Currently you'd have to declare them outside a method even though they rarely get used in more than one method.
Another use case is returning a private implementation from a method.
Sure, I can simulate this feature with internal (or private in nested classes) using a region, but it would feel so much more clean to scope it more precisely. And declare it near where it is used in the method body. This isn't about external consumers; it's about organizing internals in a cleaner way.
@HaloFour commented on Mon Mar 07 2016
Ok. In my opinion, the biggest advantage to local types over nested types is the ability to enclose its parent scope. The question is then how to deal with collisions/shadowing with that scope.
this
within the local type, whichthis
are you referring to? Would that depend on what member you might attempt to access fromthis
?The easy answer would be, "do what Java does." I don't know if that would be the correct answer, though. Java's scoping rules for local classes are somewhat complex.
@jnm2 commented on Mon Mar 07 2016
I see the rules as identical to nested types but with more limited scope:
this
. I don't see how local types would be able to maintain a reference to the outerthis
either. It would be counter-intuitive and it doesn't fit any use cases I can think of. If you need a reference, you pass it through the nested type's constructor; I'd assume the same for a local type. Sothis
would always refer to the instance of the local type.@HaloFour commented on Mon Mar 07 2016
@jnm2
So you don't think that local types should enclose the scope of their parent method? Why should local types be different than any other aspect of C# where lexical scoping is the norm? Without lexical scoping I don't really see much point to local types at all.
@HaloFour commented on Mon Mar 07 2016
To note, with local types I'd expect the following to work:
If local types also supported "hoisting" as local functions do I would expect that it would continue to work with
g
defined afterLocal
.@jnm2 commented on Mon Mar 07 2016
If you think it's valuable, I won't argue with that. I just can't think of a particular use case for dual
this
es, and I do see value in limiting scope and moving the declaration nearer to the usage even without that feature.What's the mechanism by which each instance of
Local
accesses a reference to the instance ofC
, since it's not given a field and injected through the ctor?@HaloFour commented on Mon Mar 07 2016
@jnm2
The same way local functions and lambdas do, the actual locals/fields/whatever are enclosed and promoted to fields on a state machine that is accessible to both the declaring method and the local type.
@alrz commented on Mon Mar 07 2016
I think one compelling use case for this is to avoid methods like
Observable.Create
and passing delegates which is not an attractive option at all, though, I'd prefer anonymous local classes for that specific example.@jnm2 commented on Mon Mar 07 2016
@HaloFour Conceptually that makes sense but mechanically, what does
new Local()
get transformed to? IsLocal
given a hidden field and a parameter added to each constructor invisibly?@HaloFour commented on Mon Mar 07 2016
@jnm2
Possibly. What the compiler does now for lambdas that enclose
this
or member access is that it emits a private nested type that has a field of that type and it assigns that field tothis
, then it just performs the member access directly. Something like this:I don't know if local functions did this differently, it was mentioned that they could silently insert
ref
parameters instead of needing to assign fields.As for local types, I do imagine that if you omit a constructor that one would be created which might accept
this
or other enclosed state, or if you do specify a constructor that it is silently amended to include those additional parameters. That wouldn't be unlike nested types in Java that automatically get athis
parameter even when they're not local types.@svick commented on Tue Mar 08 2016
@HaloFour Lambdas can only be passed around as delegates (object reference and
MethodInfo
pair), which makes referencing the closure easy. But types can be passed as generic type parameters orType
, which don't have anything like that.Imagine the following methods:
And I tried using them with your
Local
:Would that work? If yes, how? If not (because
Local
wouldn't actually have a parameterless constructor), then I think that would be pretty confusing.@HaloFour commented on Tue Mar 08 2016
@svick
That is an excellent point. In Java a local class can never have a parameterless constructor. It always accepts at least the instance of the parent type as an argument, even if it never uses it, as well as other enclosed variables.
I don't think that lexical scoping would be possible unless the constructor of the local type can be automatically modified by the compiler to accept the enclosed state in some form. In my opinion lexical scoping is a more valuable feature than being able to use the local type via reflection or constrained generics, and with more use cases.
Note that while I think that lexical scoping is important I don't want to hijack this proposal. If simple type scoping is all people really want then so be it. But it is my opinion that the scoping benefits alone aren't enough to warrant such a language change. Every other feature in C# that permits nested declaration enjoys lexical scoping and I think it would be quite confusing if this was the one exception. That said, I wouldn't want to just copy whatever Java does either.
@alrz commented on Tue Mar 08 2016
If we simply don't have a name for the local class, then it's impossible for a user to fall into those confusions. Basically, an anonymous type declaration instead of a local type declaration. In @HaloFour 's example, the
Local
name is just referenced once, so why do you need to name it? And if so, I think existing nested classes are good enough for that use case. In F# we do have object expressions but not local types, right?@HaloFour commented on Tue Mar 08 2016
@alrz Without a name how could you create one outside of a combined declaration/initialization? I think that would fall under #13 and that hasn't gone over well.
@alrz commented on Tue Mar 08 2016
@HaloFour #13 syntax doesn't make sense to me, it actually does combine declaration and initialization. I'm talking about (Java) anonymous classes. For parsing issue I'd suggest
new class B()
because I can't imagine any use case that you would need to combine object initialization and class declaration.@HaloFour commented on Tue Mar 08 2016
@alrz The "explicit" syntax of #13 is pretty much exactly Java anonymous classes except with C# syntax. If you're going to declare the local type but use it elsewhere you'd still need to name that type, otherwise how would you instantiate it?
@alrz commented on Tue Mar 08 2016
@HaloFour While you declaring it?
@jnm2 commented on Wed Mar 09 2016
@alrz What you are describing is exactly the topic of #13. I'd like to differentiate this topic (allowing types to be locally scoped) from that one (anonymous implementation types).
We already have anonymous locally scoped types. This issue is specifically asking for named locally scoped types with all the capabilities of nested types.
@aluanhaddad commented on Sun May 29 2016
I think that scoping(visibility) would be quite useful, but I also agree with @HaloFour that scoping(lexical) is essential. This is very useful in languages like JavaScript and should not be underestimated. Also I think the argument that lexical scoping is the norm in C# combined with the fact that lexical scoping is the best form of scoping there is, is very strong.
I think conflicting references within the inner type could be resolved by qualifying them with
this
orbase
wherethis
orbase
refers to the inner type or its base class. I need to think this over...@jnm2 commented on Wed Jun 01 2016
base
must refer to the nested type's base type. We'd need a new keyword, which makes me question the whole magic context thing. If you need a reference to the outerthis
, why not explicitly declare anowner
field in the nested type, pay-for-play? How terrible is that actually? (It feels a bit like dependency injection vs service location. Explicit and visible is better than magic and automatic.)@HaloFour commented on Wed Jun 01 2016
@jnm2
Java introduces a lot of extra syntax to deal with the implicit
this
of nested and local types. C# already diverged from that path by not having the concept of "instance" v. "static" nested types but requiring that a nested type manually declare and take a reference to its containing type. I think that the same rule for local types would be reasonable. With lexical scoping it would be as simple as declaring a local in the containing method, e.g.var self = this;
@jnm2 commented on Wed Jun 01 2016
I'm on the same page here.
This could be pay-for-play with a smart compiler, but this would mean all ctors would have to be injected invisibly and instantiation outside the method's lexical scope would be impossible. What if you need to construct and pass a nested type into a method from outside that scope? What about reflection, deserialization?
Also these things become ctor params. Assuming
public
,internal
andprivate
work as expected, a method-private type wouldn't be able to be injected into the public constructor of a method-public type.Btw field injection could work around all these issues but then you'd have to grep even more magic, worrying about where lexically the type was constructed. Let's not go there.
@HaloFour commented on Wed Jun 01 2016
@jnm2
Exactly, the enclosed values would be passed to a hidden constructor parameter, probably bundled together in a single display reference type. This is the same as with closures today.
Or, if the local type doesn't define a constructor, or the local type doesn't use those enclosed values within a constructor, those values could just be fields defined implicitly directly on the local type.
I wouldn't expect that to be possible anyway. A type defined within the scope of a method is not in scope outside of that method. You shouldn't be able to instantiate it or reference it by name anywhere but the method in which it is defined (and any other scopes within that method, e.g. other local types or closures). The actual type name should be compiler generated, mangled and inutterable, just as they are with closure display classes, and just as they are with local functions.
If you need a type that can be referenced between multiple methods you already have normal nested types.
Assuming those accessibility modifiers work as expected where? I'd expect that any accessibility modifiers on the nested type itself would be forbidden. The type is implicitly private.
Indeed, let's not. There's no reason to. Handling enclosed lexical scoping through hidden constructor parameters is already established in other languages and works quite well.
@jnm2 commented on Wed Jun 01 2016
Correct. Not sure what I was thinking there.
So... last problem is reflection and serialization (JSON.NET et al). How does a serializer instantiate a nested method type? I can see easily 50% of my use cases involving serialization.
@HaloFour commented on Wed Jun 01 2016
@jnm2
I imagine that typical reflection scenarios would "just work." The local type should be the same as any other nested type with the exception of some degree of name mangling and possibly any hidden constructor parameters to support closures. I don't think either would impact serialization via JSON.NET.
As for deserialization, I assume that this method accepts a
Stream
or astring
or some other untyped source and you're deserializing within the method to a POCO that isn't referenced outside of that method? With the exception of those hidden constructor parameters I don't see that causing an issue either. I would imagine that if you didn't enclose any scope that said parameters simply wouldn't exist in the constructor so deserialization would just work as expected also. This is exactly how local types work in Java.@jnm2 commented on Wed Jun 01 2016
JSON.NET needs a default ctor. Are you saying a nested type should have a default ctor which calls the invisible injection ctor with default values for the injected params? The net effect would be that when the nested type accesses the method variables, they are default/null if the type was constructed by JSON.NET vs if the type was constructed within the method. That doesn't sound clean to me.
@HaloFour commented on Wed Jun 01 2016
@jnm2
I'm saying that as long as the local type doesn't enclose over the method's scope then the constructor would be unaffected. But if the local type does enclose over a local or whatever then the local type would no longer have any parameterless constructors and you'd have to be aware of that when trying to use the type with something like JSON.NET.
In Java if you declare the following:
It is effectively transformed into:
@jnm2 commented on Thu Jun 02 2016
So the deserialization scenario won't work if you close over a local. Guess that makes sense.
I wonder if there is any way to close over the locals by reference so that they can be written as well as read and synced between nested type instances?
@HaloFour commented on Thu Jun 02 2016
@jnm2
Sure. Java made the decision that enclosing locals from the method scope requires that those locals be
final
, but C# has no such limitation today. I would expect that if C# were to get nested types like this that it would follow the same strategy that it does with lambdas, where it emits a separate reference type as a container for the locals:would be translated into something like this:
Although maybe something more clever could be done to avoid the additional allocation for the locals.
@Pxtl commented on Thu Aug 25 2016
This looks like to be the only open request for something analogous to Java's anonymous inner classes, so +1 for this. I've been running into this a lot where I have a collection of singletons - that is, a collection where each member is an instance of a different subclass of a common abstract class. In Java this is really easy with anonymous inner classes - basically allowing me to do a full class declaration in the body of a method, one that captures references to the surrounding scope, and instantiate it in the inner-class-declaration expression. Extremely useful. Otherwise, you either have to use reflection to populate the singleton-collection by searching through the classes, or you have to define the classes and list separately and maintain redundant code (and somebody will always forget to add an instance of the class to the singleton-collection).
Beta Was this translation helpful? Give feedback.
All reactions