c# - Any clean way for generic parent to get type of child?


  • BINNED

    I still don't know what's speaking against the obvious two-liner solution or a template version of it. Something like the following (C++) should be possible in C#. Repeating the class name once, as in the OP, sounds better than reflection and other horribleness.

    class Diagnostics final {
        Diagnostics() = default;
    public:	
        static Diagnostics& instance() { static Diagnostics self; return self; }
    };
    


  • @topspin said in c# - Any clean way for generic parent to get type of child?:

    I still don't know what's speaking against the obvious two-liner solution or a template version of it. Something like the following (C++) should be possible in C#. Repeating the class name once, as in the OP, sounds better than reflection and other horribleness.

    class Diagnostics final {
        Diagnostics() = default;
    public:	
        static Diagnostics& instance() { static Diagnostics self; return self; }
    };
    

    In C#, GetType() should always return the derived non-generic Type. Unless some idiot overloads it like the following.

    class GenericClass<T>
    {
      public Type GetType()
      {
        return typeof(int);
      }
    }
    


  • @Cursorkeys said in c# - Any clean way for generic parent to get type of child?:

    I have a generic class:

    public class PhoenixSingleton<TSingletonType>
            where TSingletonType : PhoenixSingleton<TSingletonType>,new()
    {
    }
    

    And this just looks janky and is annoying me:

    class Diagnostics : PhoenixSingleton<Diagnostics>
    {
    }
    

    Is there any other way to get the type back into the parent that I'm missing?

    Just use GetType() in parent. It works for me. Since you have an instance, GetType of instance will return the derived type on that instance.


  • And then the murders began.

    @WPT said in c# - Any clean way for generic parent to get type of child?:

    In C#, GetType() should always return the derived non-generic Type. Unless some idiot overrides it like the following.

    But... it's not virtual, so it can't be overridden. It can be overloaded, but the parent class calling GetType will never see it, but instead will see the expected implementation from Object.



  • @Unperverted-Vixen
    My mistake. Fixed it.


  • Banned

    @error said in c# - Any clean way for generic parent to get type of child?:

    I actually suggested static local variables as a feature to the TypeScript team and they shot it down ruthlessly.

    I still think they'd be handy but I agree now that they've decided to align themselves closer to ECMAScript.

    Static local variables are a horrible idea. About the only thing they're actually useful for is implementing singleton pattern, which is a horrible idea itself.


  • Discourse touched me in a no-no place

    @Gąska said in c# - Any clean way for generic parent to get type of child?:

    About the only thing they're actually useful for is implementing singleton pattern, which is a horrible idea itself.

    They're useful for things which are expensive to initialise, but which are quite possibly not needed; they let you avoid having to do the expensive initialisation. Their use is just the same as with static variables with wider scopes, except now you've got a much more limited scope (a single function).

    You probably don't need them very often.


  • Notification Spam Recipient

    @Gąska said in c# - Any clean way for generic parent to get type of child?:

    singleton pattern, which is a horrible idea itself.

    What exactly is so horrible about it?


  • Banned

    @MrL said in c# - Any clean way for generic parent to get type of child?:

    @Gąska said in c# - Any clean way for generic parent to get type of child?:

    singleton pattern, which is a horrible idea itself.

    What exactly is so horrible about it?

    I'm feeling lazy today so I'll just link to one of thousands of articles from all over internet that explain it in depth.

    https://www.davidtanzer.net/david's blog/2016/03/14/6-reasons-why-you-should-avoid-singletons.html

    In short - Singletons are bad for the same reason global variables are bad.

    Fucking Ctrl+Enter.



  • @MrL
    The risk of abuse, leading to tightly coupled dependencies lying all over the place, far outweighs the benefits of easy access to the singleton.
    There might be valid use case for singleton, like object describing application state, but for the rest of the modules, there is more arguments for being able to control component lifecycles when using them.


  • Notification Spam Recipient

    @Gąska said in c# - Any clean way for generic parent to get type of child?:

    @MrL said in c# - Any clean way for generic parent to get type of child?:

    @Gąska said in c# - Any clean way for generic parent to get type of child?:

    singleton pattern, which is a horrible idea itself.

    What exactly is so horrible about it?

    I'm feeling lazy today so I'll just link to one of thousands of articles from all over internet that explain it in depth.

    https://www.davidtanzer.net/david's blog/2016/03/14/6-reasons-why-you-should-avoid-singletons.html

    In short - Singletons are bad for the same reason global variables are bad.

    A lot of text written to say "use containers for absolutely everything".

    @WPT said in c# - Any clean way for generic parent to get type of child?:

    @MrL
    The risk of abuse, leading to tightly coupled dependencies lying all over the place, far outweighs the benefits of easy access to the singleton.

    Ah, the good old "if you do it 300 times it will be a problem, so don't do it ever".

    I find it funny (and irksome) how in this industry radical solutions spread like wildfire. It rarely is "consider if using this is beneficial and remember about its downsides", but rather "never use it for anything or horrible things will happen" or "this is the fundamental way of doing things, use it everywhere and always".


  • Discourse touched me in a no-no place

    @WPT said in c# - Any clean way for generic parent to get type of child?:

    There might be valid use case for singleton, like object describing application state, but for the rest of the modules, there is more arguments for being able to control component lifecycles when using them.

    Singleton-by-configuration is fine. Singleton-baked-into-the-code is not.


  • Banned

    @MrL singletons are bad even if you use only one singleton, if you use it for the wrong thing. OP's Diagnostics and other debug tools that essentially amount to println() I'm okay with, but only because no part of the program actually retrieves any data from them, so this hack doesn't hurt that much, and it's not going to change almost at all throughout the product's entire lifecycle. For everything else, singletons are never the right solution. They might be sometimes bearable as a quick and dirty hack because making things work now is more important than making things work in the long run, but they're never right. Limiting yourself to only one instance of a class ever is just such a huge decision that has big implications for every part of your codebase that touches it that unrolling it is guaranteed to be a PITA of epic proportions - and most of the time, you will have to unroll it eventually, because a business requirement will come up that you suddenly need two instances of the thing that there could only be one of until now.

    Compare designing for having many independent instances of a class right from the start, and ending up with only one instance all the time in practice - this way around it's trivial to support because 1 is just a special case of N, and when the requirements change so that 1 isn't 1 anymore, it'll be MUCH less painful to adapt.

    Also, testing.


  • Notification Spam Recipient

    @Gąska said in c# - Any clean way for generic parent to get type of child?:

    @MrL singletons are bad even if you use only one singleton, if you use it for the wrong thing. OP's Diagnostics and other debug tools that essentially amount to println() I'm okay with, but only because no part of the program actually retrieves any data from them, so this hack doesn't hurt that much, and it's not going to change almost at all throughout the product's entire lifecycle. For everything else, singletons are never the right solution. They might be sometimes bearable as a quick and dirty hack because making things work now is more important than making things work in the long run, but they're never right. Limiting yourself to only one instance of a class ever is just such a huge decision that has big implications for every part of your codebase that touches it that unrolling it is guaranteed to be a PITA of epic proportions - and most of the time, you will have to unroll it eventually, because a business requirement will come up that you suddenly need two instances of the thing that there could only be one of until now.

    Compare designing for having many independent instances of a class right from the start, and ending up with only one instance all the time in practice - this way around it's trivial to support because 1 is just a special case of N, and when the requirements change so that 1 isn't 1 anymore, it'll be MUCH less painful to adapt.

    Also, testing.

    Making big changes is hard, don't implement things you'll have to change later. Nothing specifically about singletons and their huge, gigantic, horrible, catastrophic flaws.


  • Banned

    @MrL

    • Global mutable state. Never ending source of fun in multithreaded code (among other problems it creates).
    • Cannot be stubbed by definition (unless you devise some mechanism for replacing the implementation of the singleton depending on whether it's testing or production build, at which point you could've just as well made it non-singleton, it'd be just as much work).
    • The assumption that there can only ever be one of something is going to cascade across your entire codebase, and it's the type of assumption that's the most prone to becoming false over time.
    • Singleton objects have a tendency of becoming God objects because it's just so convenient that you can access this thing from everywhere.

    The problem isn't with the singleton itself. The problem is with everything that the singleton pattern represents. It leads to very bad code. And it's entirely avoidable. Whenever you want to add a singleton, making a non-singleton instead is just a tiny bit of additional work, and it's nearly guaranteed to pay off in the long run.


  • Notification Spam Recipient

    @Gąska said in c# - Any clean way for generic parent to get type of child?:

    • Global mutable state. Never ending source of fun in multithreaded code (among other problems it creates).

    You may want global mutable state. You may be in single thread environment. You can mutex around the fun.

    • Cannot be stubbed by definition (unless you devise some mechanism for replacing the implementation of the singleton depending on whether it's testing or production build, at which point you could've just as well made it non-singleton, it'd be just as much work).

    You may not need/want stubbing. Or it may not make sense.

    • The assumption that there can only ever be one of something is going to cascade across your entire codebase, and it's the type of assumption that's the most prone to becoming false over time.

    It's exactly the same when you use an interface and it changes - you have to cascade the change across your entire codebase. And such changes happen all the time.

    • Singleton objects have a tendency of becoming God objects because it's just so convenient that you can access this thing from everywhere.

    'You can misuse it, so don't use it ever' again.

    God objects can be done in multitude of ways. Just don't do them.

    The problem isn't with the singleton itself. The problem is with everything that the singleton pattern
    represents.

    Which is what?

    It leads to very bad code.

    I still don't see what's so very bad here, and what's inherent to singletons and not everything else.

    And it's entirely avoidable. Whenever you want to add a singleton, making a non-singleton instead is just a tiny bit of additional work, and it's nearly guaranteed to pay off in the long run.

    Except when you have to bend backwards and devise entire mechanisms for tossing around current state, just to say 'well, at least I don't use singletons'.


  • Banned

    @MrL said in c# - Any clean way for generic parent to get type of child?:

    @Gąska said in c# - Any clean way for generic parent to get type of child?:

    • Global mutable state. Never ending source of fun in multithreaded code (among other problems it creates).

    You may want global mutable state.

    You may think you want. But most often it's not worth it. The worst thing is, you only start seeing it's not worth it two years down the line, and then it's too late and the only solution is rewriting half of the project. BTDT.

    You may be in single thread environment.

    It's just a matter of time until you want something to be done in parallel. To prevent freezing the entire GUI for the duration of the operation, for example.

    You can mutex around the fun.

    Properly locking all the moving parts is a lot of fun itself. Unless your idea of locking is the same as Python's - a single global mutex that reduces all environments to a single thread environment.

    • Cannot be stubbed by definition (unless you devise some mechanism for replacing the implementation of the singleton depending on whether it's testing or production build, at which point you could've just as well made it non-singleton, it'd be just as much work).

    You may not need/want stubbing.

    Only if you don't need/want unit or module tests. I have a very strong opinion of programmers who think they don't need/want unit or module tests.

    Or it may not make sense.

    Singletons are usually used to communicate with other modules in the application. This is the very first thing you want to stub out in tests.

    • The assumption that there can only ever be one of something is going to cascade across your entire codebase, and it's the type of assumption that's the most prone to becoming false over time.

    It's exactly the same when you use an interface and it changes - you have to cascade the change across your entire codebase. And such changes happen all the time.

    If your data type changes from int to float, you just replace int with float everywhere and you're (mostly) done. If the class that previously only ever had one instance now can have multiple instances... hoo boy, that's going to change a lot of things. Suddenly all other things have to be multiplied too. Lists of objects become lists of lists. A previously threadsafe operation needs to be reworked from scratch. And so on and so on. BTDT. De-singletonizing is a really major change; few things can compare.

    • Singleton objects have a tendency of becoming God objects because it's just so convenient that you can access this thing from everywhere.

    'You can misuse it, so don't use it ever' again.

    Hey, it's a valid criticism. You're not alone in the project, your code will be touched by juniors eventually. If you get equivalent functionality with equal effort but without all these problems, why do something that does have these problems?

    It's not just that singletons allow God objects. They encourage God objects by making them super easy. Also, dependency graph will absolutely suck.

    I agree this is not that big of a problem, compared to all the other problems with a singleton. But it's still a problem.

    And it's entirely avoidable. Whenever you want to add a singleton, making a non-singleton instead is just a tiny bit of additional work, and it's nearly guaranteed to pay off in the long run.

    Except when you have to bend backwards and devise entire mechanisms for tossing around current state

    Like a constructor?

    just to say 'well, at least I don't use singletons'.

    And to avoid all the problems mentioned above.


  • Considered Harmful

    @Gąska said in c# - Any clean way for generic parent to get type of child?:

    @error said in c# - Any clean way for generic parent to get type of child?:

    I actually suggested static local variables as a feature to the TypeScript team and they shot it down ruthlessly.

    I still think they'd be handy but I agree now that they've decided to align themselves closer to ECMAScript.

    Static local variables are a horrible idea. About the only thing they're actually useful for is implementing singleton pattern, which is a horrible idea itself.

    I agree singletons suck, but static variables have other uses.

    Any time a function needs state, really (which defies the definition of function, to some people). Luckily in TypeScript/JavaScript all you really need is a closure with a variable defined inside it, then return a function that uses it. (A global variable would also work, but pollutes the global scope and allows unwanted access.)

    Uses:

    • memoization
    • nextid (number sequence)
    • seeded PRNG

  • Considered Harmful

    @MrL said in c# - Any clean way for generic parent to get type of child?:

    Ah, the good old "if you do it 300 times it will be a problem, so don't do it ever".

    Scalability is a chief concern to me. The longer a project lives, the more it will grow, and if it's not designed to grow, you will suffer for it.


  • Banned

    @error said in c# - Any clean way for generic parent to get type of child?:

    Uses:

    • memoization
    • nextid (number sequence)
    • seeded PRNG

    Instead of a static local, you can use an object for each of these.


  • Considered Harmful

    @Gąska True, but the more I use JS/TS, the less I use OOP patterns with it.

    Classes create as many problems as they solve in JS.


  • Notification Spam Recipient

    @Gąska said in c# - Any clean way for generic parent to get type of child?:

    You may think you want. But most often it's not worth it. The worst thing is, you only start seeing it's not worth it two years down the line, and then it's too late and the only solution is rewriting half of the project. BTDT.

    Same thing with any other interface - the more it's used, the harder it's to change.

    It's just a matter of time until you want something to be done in parallel. To prevent freezing the entire GUI for the duration of the operation, for example.

    Yeah, switching to parallel would be such a smooth ride if not for singletons.

    Properly locking all the moving parts is a lot of fun itself. Unless your idea of locking is the same as Python's - a single global mutex that reduces all environments to a single thread environment.

    Depends on how many moving parts there are, how they move and what accesses them. Properly locking stuff is not a problem inherent to singletons.

    Only if you don't need/want unit or module tests. I have a very strong opinion of programmers who think they don't need/want unit or module tests.

    If the singleton is an integral part of some unit operation, then stubbing it doesn't make sense. Unless you like testing units mocked so hard that they don't do anything.

    Or it may not make sense.

    Singletons are usually used to communicate with other modules in the application. This is the very first thing you want to stub out in tests.

    Just set the state in the singleton to what you want.

    If your data type changes from int to float, you just replace int with float everywhere and you're (mostly) done.

    No, I said 'when interface changes' - methods, parameters, returned types, properties change.

    If the class that previously only ever had one instance now can have multiple instances... hoo boy, that's going to change a lot of things. Suddenly all other things have to be multiplied too. Lists of objects become lists of lists. A previously threadsafe operation needs to be reworked from scratch. And so on and so on. BTDT. De-singletonizing is a really major change; few things can compare.

    "things have to be multiplied", "Lists of objects become lists of lists", wth are you talking about?
    Change the way instance is acquired, check if access is thread safe and that's all.

    Hey, it's a valid criticism. You're not alone in the project, your code will be touched by juniors eventually.

    Juniors are to be taught and guided, not shielded from problems.

    It's not just that singletons allow God objects. They encourage God objects by making them super easy.

    There's a lot of stupid stuff that's super easy, yet somehow we manage to avoid it.

    Also, dependency graph will absolutely suck.

    Who cares.

    Like a constructor?

    Like synchronizing singular stuff between many instances.


  • Banned

    @MrL said in c# - Any clean way for generic parent to get type of child?:

    It's just a matter of time until you want something to be done in parallel. To prevent freezing the entire GUI for the duration of the operation, for example.

    Yeah, switching to parallel would be such a smooth ride if not for singletons.

    In comparison? Absolutely. The biggest roadblock in parallelizing is always shared state. Singleton is the ultimate in shared state.

    Only if you don't need/want unit or module tests. I have a very strong opinion of programmers who think they don't need/want unit or module tests.

    If the singleton is an integral part of some unit operation, then stubbing it doesn't make sense.

    If the singleton is an integral part of some unit operation, then either you're testing the singleton itself, or you're doing unit testing wrong.

    Or it may not make sense.

    Singletons are usually used to communicate with other modules in the application. This is the very first thing you want to stub out in tests.

    Just set the state in the singleton to what you want.

    And now whenever there's a bug, you wonder "is it the thing I'm testing that's wrong, or is it one of the singletons it uses? Or maybe the carefully crafted recipe that I'm using to set up the singleton to the state I want it to be in doesn't set it to what I want and needs to be updated?" Result: much more time spent debugging.

    If your data type changes from int to float, you just replace int with float everywhere and you're (mostly) done.

    No, I said 'when interface changes' - methods, parameters, returned types, properties change.

    Returned types? Exactly what I said. Property names? A quick Find&Replace in most cases. Method parameters? Just supply the method with this new thing it wants and you're done. Method semantics change? Adapt the code to the new paradigm; the method is probably used in just a few places and the change is pretty straight forward.

    Desingletonize? Now you have to review the entire codebase for all direct and indirect dependencies of this singleton, and make note of every single place that also need to be "multiplied" now that a child object that previously could be owned by the one and only singleton, can now come from one of several parents, and objects from different parents usually cannot be mixed with each other so you need to track that too now, and it wasn't done previously (why would you, if the parent was singleton).

    Some changes require more work than others. Sometimes much more. Desingletonizing is among those that require the most changes, only surpassed by things like switching the underlying platform for the whole project and the like.

    Hey, it's a valid criticism. You're not alone in the project, your code will be touched by juniors eventually.

    Juniors are to be taught and guided, not shielded from problems.

    There's perfect world, and there's real life. If I can somehow reduce the damage they do, I will.

    It's not just that singletons allow God objects. They encourage God objects by making them super easy.

    There's a lot of stupid stuff that's super easy, yet somehow we manage to avoid it.

    This forum is in fact dedicated to all the ways we successfully avoid stupid stuff. Especially the Side-Bar WTF category has it very well documented that we never encounter stupid stuff in our line of work.

    Also, dependency graph will absolutely suck.

    Who cares.

    Any person who introduces a change to any of the myriad of interdependent components and needs to make sure nothing else breaks.

    Like a constructor?

    Like synchronizing singular stuff between many instances.

    Why would you synchronize singular stuff between many instances? Just create one instance that holds all the stuff.


  • Banned

    @error said in c# - Any clean way for generic parent to get type of child?:

    @Gąska True, but the more I use JS/TS, the less I use OOP patterns with it.

    Classes create as many problems as they solve in JS.

    There's a reason I said an object and not a class. Although closure works too (I consider it a kind of object - it couples behavior with state, after all).


  • 🚽 Regular

    @WPT said in c# - Any clean way for generic parent to get type of child?:

    @Cursorkeys said in c# - Any clean way for generic parent to get type of child?:

    I have a generic class:

    public class PhoenixSingleton<TSingletonType>
            where TSingletonType : PhoenixSingleton<TSingletonType>,new()
    {
    }
    

    And this just looks janky and is annoying me:

    class Diagnostics : PhoenixSingleton<Diagnostics>
    {
    }
    

    Is there any other way to get the type back into the parent that I'm missing?

    Just use GetType() in parent. It works for me. Since you have an instance, GetType of instance will return the derived type on that instance.

    It may just be me being dense, but I don't see how. You'd need to have a singeton instance first and to do that you'd have already have to have gotten the type into the singleton class somehow.

    A minimum viable program would currently be:

    public class BasicSingleton<TSingletonType>
            where TSingletonType : BasicSingleton<TSingletonType>, new()
    {
        private static TSingletonType _singletonInstance;
        static readonly object Padlock = new object();
    
        public static TSingletonType Instance
        {
            get
            {
                lock (Padlock)
                {
                    return _singletonInstance ?? (_singletonInstance = new TSingletonType());
                }
            }
        }
    }
    
    public class FooSingleton : BasicSingleton<FooSingleton>
    {
        public void DoAThing(void)
        {
            Trace.WriteLine("I'm a useless Singleton implementation!");
        }
    }
    
    static class Program
    {
        [STAThread]
        static void Main()
        {
            var uselessSingleton = FooSingleton.Instance;
            uselessSingleton.DoAThing();
        }
    }
    

  • Considered Harmful

    Two issues:

    • the inheritance is not really doing anything; all members are static, you're just aliasing the static members
    • it requires a public default constructor, so you can easily violate the single instance constraint - probably without even realizing it was ever intended to be a singleton

  • 🚽 Regular

    @error said in c# - Any clean way for generic parent to get type of child?:

    Two issues:

    • the inheritance is not really doing anything; all members are static, you're just aliasing the static members

    I can't work out exactly what you mean here, could you explain it in an expanded way? I'm a self-taught programmer, so it's most definitely me that's the problem.

    • it requires a public default constructor, so you can easily violate the single instance constraint - probably without even realizing it was ever intended to be a singleton

    Yep, that is a real problem. I can't see a way to fix that at the moment though.


  • Considered Harmful

    @Cursorkeys said in c# - Any clean way for generic parent to get type of child?:

    I can't work out exactly what you mean here, could you explain it in an expanded way? I'm a self-taught programmer, so it's most definitely me that's the problem.

    FooSingleton.Instance is just another way of writing BasicSingleton<FooSingleton>.Instance, and my linter will complain that this is the case.


    Additional minor nit: you always acquire the lock, even if the singleton is already initialized. The (annoying) pattern to avoid this perf hit is

    var si = _singletonInstance;
    if( si != null ) return si;
    lock( PadLock ) {
      return _singletonInstance ?? (_singletonInstance = new TSingletonType());
    }
    

    (Yes, you have to check it twice, because it could have changed before you acquired the lock. Yes, you have to put in a variable because it could have changed between the test and the early return.)


  • Java Dev

    @error said in c# - Any clean way for generic parent to get type of child?:

    Yes, you have to put in a variable because it could have changed between the test and the early return.

    Only if the member variable can change after initially being set. Which I think isn't expected with this pattern?


  • Considered Harmful

    @PleegWat said in c# - Any clean way for generic parent to get type of child?:

    @error said in c# - Any clean way for generic parent to get type of child?:

    Yes, you have to put in a variable because it could have changed between the test and the early return.

    Only if the member variable can change after initially being set. Which I think isn't expected with this pattern?

    Not expected, but theoretically possible - defensive coding.

    Plus, it's a good habit to write it in a resilient way because the same assumptions might not always apply or be readily apparent.



  • @Cursorkeys
    I can't see any "cleaner" way of doing it without making BasicSingleton abstract and abstracting away the Instance property... but then it introduces a whole lot of other complexities... This is a very deep rabbit hole...

    Just screw the inheritance... It really does not make any sense to implement it in such a use case.

    Use a service locator pattern if you need to for the remaining TSingleton... It makes more sense.


  • Considered Harmful

    ITT "I'm too lazy and too clever to type the pattern in the universally standard way, so let me invent a more complicated, less safe, slower, arcane way of doing the same thing (except it forces a specific base class and ultimately results in more code)."



  • @error
    Sometimes, I get my mind corrupted and confused after having to read/refactor too many anti-patterns...
    My expected bar of code standards gets lowered each time I have to try and figure what the code is trying to achieve in the first place.


  • Considered Harmful

    I think the Gang of Four version of the pattern still holds best.

    Though there is Lazy.

    class Foo {
      private Foo() {}
      private static readonly Lazy<Foo> _instance = new Lazy<Foo>( () => new Foo() );
      public static Foo Instance => _instance.Value;
    }
    

  • Considered Harmful

    Good old Kotlin.

    object Foo {
        fun bar() {}
    }
    fun main() {
        println(Foo)
        Foo.bar()
    }
    

  • Considered Harmful

    @pie_flavor said in c# - Any clean way for generic parent to get type of child?:

    Good old Kotlin.

    object Foo {
        fun bar() {}
    }
    fun main() {
        println(Foo)
        Foo.bar()
    }
    

    Looks like:

    public static class Foo {
        public static void Bar() {}
    }
    

  • Considered Harmful

    @error Except for println(Foo) is valid. The object is both the class and the singleton instance at once.


  • Considered Harmful

    @pie_flavor I've been considering learning Kotlin for Android dev. Do you think it offers significant advantages to Java?


  • Discourse touched me in a no-no place

    @pie_flavor I take it you can also declare that it is a subclass of some other class and/or implements some interfaces?


  • Considered Harmful

    @error Ridiculously so. It makes nearly every aspect of Java development five times easier, but particularly the clunky Java 6 style of API that Android is. Nullability is explicit and checked at compile time and runtime, everything's an expression, you can implement an interface using another instance of that interface in a one-liner, lambdas can be inlined for zero-cost expressivity, etc.


  • Considered Harmful

    @dkf You can. Although you can't subclass it, because then there'd be more than one instance.


  • Discourse touched me in a no-no place

    @pie_flavor said in c# - Any clean way for generic parent to get type of child?:

    Although you can't subclass it, because then there'd be more than one instance.

    Of course.


  • 🚽 Regular

    @pie_flavor said in c# - Any clean way for generic parent to get type of child?:

    @error Except for println(Foo) is valid. The object is both the class and the singleton instance at once.

    I haven't touched Kotlin much, but quickly perusing their documentation I think I prefer the approach using companion objects:

    class Foo {
      companion object Instance {
        fun bar() {}
      }
    }
    
    fun main() {
      println(Foo.Instance)
      println(Foo) // Same thing
    
      Foo.Instance.bar()
      Foo.bar() // Same thing
    }
    

    Note that, even though the members of companion objects look like static members in other languages, at runtime those are still instance members of real objects, and can, for example, implement interfaces

    However, on the JVM you can have members of companion objects generated as real static methods and fields, if you use the @JvmStatic annotation.

    Correct me if I'm wrong. (of course you will)


  • Considered Harmful

    While we're at it...

    @pie_flavor said in c# - Any clean way for generic parent to get type of child?:

    fun main()

    seeing the word “fun” appear so often in Kotlin code is distracting and reduces code readability

    It's fun! 🍹


  • Banned

    @Applied-Mediocrity Rust has fn. It's funny because it's both even shorter and less triggering at the same time.

    Personally, I don't really care either way, though I slightly prefer not having to write work function every time. It's a bit too long for a commonly used keyword.



  • @Applied-Mediocrity Now there's some proper petty bikeshedding.


  • Discourse touched me in a no-no place

    @cvi said in c# - Any clean way for generic parent to get type of child?:

    Now there's some proper petty bikeshedding.

    All that's missing is :doing_it_wrong: coming along and closing the discussion while banning the original asker as NOT WELCOME HERE. Which is pretty damn ironic given that it's a necro'd thread on a :disco:🐎 instance…



  • @dkf said in c# - Any clean way for generic parent to get type of child?:

    All that's missing is :doing_it_wrong: coming along and closing the discussion while banning the original asker as NOT WELCOME HERE.

    Dunno. :doing_it_wrong: kinda came across like somebody hating fun as well -- might be welcoming other fun-hating people.


  • 🚽 Regular

    roschlau said in that thread:

    There even is one upside to the keyword fun over the other alternatives - it has the same number of characters as val and var, making classes just a tad more readable because all the names for properties and functions start on the same column.

    This dude gets it.


  • Considered Harmful

    @Zecc You don't have to name the companion object (in which case it gets named Companion). Anyway, singletons should be object; companion objects are for when you want to associate an object with a class, which is rarely the case for singletons. In fact a companion object is nothing more than an object nested in a class.


Log in to reply