Page MenuHomePhabricator

Do not allow static-function polymorphism
Closed, ResolvedPublic

Description

Right now we support static-function polymorphism. However, we probebly should not do that, since C# and probably other cannot support that exotic feature.

static-function polymorphism is that you can override a class function of class A in class B where class B inherits from class A.

bu5hm4n created this task.Feb 1 2019, 6:35 AM
bu5hm4n moved this task from Restricted Project Column to Restricted Project Column on the Restricted Project board.Feb 4 2019, 6:04 AM
bu5hm4n renamed this task from Do not allow static polymorphism to Do not allow static-function polymorphism.Feb 6 2019, 5:41 AM
bu5hm4n updated the task description. (Show Details)

@lauromoura How is that handled in c# ?

you can have in eo:
A.eo :

class A {
   @class bla_a { ... }
}

B.eo :

class B {
   implements {
      A.bla_a;
   }
}

You can call now a_bla_a(A_CLASS); or a_bla_a(B_CLASS) which would be the calling the implementation of A_CLASS or B_CLASS. How is that handled in C# ? Should we allow that ?

Actually, looking twice at this, we add every single class function to the vtable of the class, which is IMO quite a waste. We should not override this, as the only two languages supporting such a feature are actaully javascript and python where you can also edit vtables in the runtime.

My proposal: Lets drop the class functions from there, class functions in .eo files will just produce normal c functions which can be binded, *no* parameters required. (@zmike, @segfaultxavi, @cedric, comments ?)

Given the headaches that mixins have given us, I'd say we avoid exotic features, yes.
API-wise, it's just a matter of Eolian erroring out when it finds a @class method inside an implements section, right?

No, we should also not allow this in eo at all. And change Eolians generation.

Sure sure, I was asking "API-wise", that is, the only change that affects the API :)

APIs, adjusted:

  • efl_class_functions_set class_ops should go away
  • Every class API generated by Eolian will not have the first API
  • Every implementation API will loose the first and second parameter.

@lauromoura How is that handled in c# ?

you can have in eo:
A.eo :

class A {
   @class bla_a { ... }
}

B.eo :

class B {
   implements {
      A.bla_a;
   }
}

You can call now a_bla_a(A_CLASS); or a_bla_a(B_CLASS) which would be the calling the implementation of A_CLASS or B_CLASS. How is that handled in C# ? Should we allow that ?

C#-wise, this is unsupported (actually I think we don't even generate the implement). static functions there are local to the class they are declared in.

@lauromoura I read out of your reply that you also want to see this feature going ?

@lauromoura I read out of your reply that you also want to see this feature going ?

Do you mean simplifying class functions to be plain C functions? Absolutely :)

Nice, will work at the weekend on that :)

tasn added a subscriber: tasn.EditedWed, Aug 7, 11:23 AM

I just finished a big damn rant on IRC about this. Honestly, did it not occur to you to ASK why things were done this way? I'm on IRC every day. I still have my email address. No one asked.
This was talked about so many times over the years. Argued back and forth. It was set the way it was set for a reason.

No, C# not supporting class function overrides is not an excuse. It's something we discussed, anticipated and had solutions for already in 2014.

As I said on IRC: C doesn't have classes, should we just drop classes then? Python doesn't have types, why not drop types?

This is absolutely mental that you went on with this without at least asking! I'm not saying you made the wrong decision here (though I believe you are), I just find it crazy that you'd change something so fundamental without asking the people who worked on it for literally years. I didn't get a single email or a single text. Never mind the lack of respect for other's people work. It's just stupid and wasteful to keep on rewriting other people's work without first asking.

Edit: sorry for the angry tone, it's just so terribly annoying and I just don't get why you didn't ask. Either me directly or on the ML which I mostly read. I also don't understand why none of the "reviewers" did so either. What's the point of this whole review system if it seems like a way to avoid actual review and actual discussion? Yeah, I wouldn't have reviewed your code, but I would have answered your questions.

Edit 2: just a small clarification after chatting on IRC: I'm not asking for consent. What I'm asking for is for you to do even the slightest due diligence and research before making such massive changes. Like asking the person who wrote the piece of code you're fundamentally changing why things were done the way they were.

zmike added a project: BBQ.Wed, Aug 7, 11:51 AM

Okay, after i have received another rant via PM, with the conclusion that i have a social problem:

  1. No OOP framework does support that. Not a single one, all you can do is basically overloading but newer overwriting, which leaves you with static dispatching instead of dynamic dispatching. Coming from a math background, class functions in a argebraic sense are also static dispatched, and the same, per group / class. (https://en.wikipedia.org/wiki/Class_function_(algebra))
  2. Whatever you have want yo model with a overwritable class function, you still can do it. Just have a property that returns an object that implements the API. Higher hirachies can pass there theire own object, with theire own implementations. (Whatever was possible still is possible)

With the decision that was taken, we also now have the term "class function" aligned with the rest of the OOP world. Models that used that before are still beeing able to be modeled with the same call chain like before.

tasn added a comment.Thu, Aug 8, 3:35 AM

I didn't say you have social problems, I was complaining exactly like the above. I said the big issue with this change is the broken process (which is a social aspect, not technical) that lead to you changing a massive piece of code without asking *anyone* that's been involved in it's creation and design when I'm on IRC, mail and read the ML. The only one of the "reviewers" that actually maybe was involved is q66, but he said he wasn't asked to review any proposals (as evident by this ticket and lack of participation) but rather to review the code. It's not about me, I just don't understand why you'd make such a big change without first gathering information.

  1. I don't know if you mean this in a technical nit-picky way or how it actually looks, but here's JS code:
class A {
  static foo() {
    console.log('A');
  }
}

class B extends A {
  static foo() {
    super.foo();
    console.log('B');
  }
}

B.foo();

Here's some python code:

class A:
    @classmethod
    def foo(cls):
        print('A')


class B:
    @classmethod
    def foo(cls):
        A.foo()
        print('B')


B.foo()

I guess this covers this "not a single one". I'm a bit rusty in Java and other languages, but I can probably do it there too.

  1. Not sure I follow what you mean. But following the same logic it was possible before your change too. Them being equivalent is not a reason to change...

Again, I'm not sure I follow what you mean with follow the rest of the OOP world, because as shown above, the rest of the OOP world disagrees with you.

I also know you made this change because of C#, but languages only supporting a subset of what eolian does is something we anticipated and we have solutions for, so this is also not a reason. This can be solved in generators that need this extra special weird behaviour.

Anyhow, this change is also wrong on a different level. If you don't think class functions are needed and want to remove them, then they should be removed and probably have something like T8118 which I suggested before I heard about this change you did. Because now you have functions that have nothing to do with the class grouped in the class. So you need to either fix them back, or remove class functions altogether, but what you have now is somewhere in between that doesn't make sense.

Just to remphasise: all of this you could have gotten before doing the change and being so committed to it as you are now if you only just asked. Fixing the C# bindings is easy, and it's crazy to change our abstract language just because one specific language is lacking.

Let's stick to the technical, the rest will end up in another rant and more weird arguements that lead to the conclusion that I need to ask you. Note is taken "ask Tom for changes in eo"

What we had before are *not* class functions.
Class functions are equal on each and every inheritor of the initial definition. They can only be overloaded, not overwritten.
I don't want to comment on your JavaScript example as I do not know JavaScript well. However, I would claim that we probably should not align our object system with the most hacky language out there.
For your python example: you explicitly call A, you do not have a reference object there. And again, you are in a language that automatically dynamic dispatched *everything* dynamically if there is a ".".

If you go to languages like c++ static function calls cannot be overwritten, same for java, same for c#, same for objective c (the list is very long).

The problem with your proposal is that there is no explicit place where those functions are located in. So languages that do not have standalone functions will run into trouble, as they cannot bind in a same way to those APIs. What we have right now solves that, as we have all the APIs in a defined scope.

To sum up: not one language is lacking, a giant set of languages does not support that (basically all languages that do have a traditional stable setup). Having class functions like c++ java and so on does solve a whole range of problems for us, so I am not really in favour of what was there before, and also not in favour of your RFC.

tasn added a comment.Thu, Aug 8, 4:58 AM

Stop trying to twist my words and start reading them. I never fucking said ask Tom for changes in eo. I said, when you fundamentally change existing code, ask the people who wrote it why it was the way it was. Not just me, not just Eo. I talked to raster a lot when I redid the text system way back when, I talked to everyone a lot when I did the object system, I talked to cedric when I touched the relevant edje parts. It's just common sense to ask people who actually know the code why things that you find weird are done the way they were. I don't understand why you keep on trying to ridicule this statement. It's obvious and should be the basis to everything you do.

Back to the topic: I believe you can actually use super in Python to make my code even cleaner (my Python game is weak), but it doesn't matter, the example still holds with:

class A:
    @classmethod
    def foo(cls):
        print('A')


class B:
    @classmethod
    def foo(cls):
        # REMOVED: A.foo()
        print('B')


B.foo()

It's still a useful way to have a unified interface on the class. One place where class functions are used extensively (including inheritance) is when you have a factory or a singleton kind of function where you want to change how it's init when inheriting. A very common pattern.

Here's another example in Java:

public class Main {

    public static class A {
        public static void foo() {
            System.out.println("A");
        }
    }

    public static class B extends A {
        public static void foo() {
            System.out.println("B");
        }
    }

    public static void main(String[] args) {
        B.foo();
    }
}

The list is only long just because you are adding languages that shouldn't be there. I bet it also works on C++ and Obj-C which I have passing familiarity in, and I never did C# so can't comment, but I'm willing to bet it's possible there too. As I said, the factory and singleton patterns are both very common.
When I built Eo, I researched all the main languages and played with most of them, so I'm very surprised by these (as proven above: false) claims.

My proposal: I explicitly addressed your issue about languages that don't have that. Heck I even mentioned Java by name. They are namespaced like everything else. If it's a language that requires a class like Java and C#, put it in a special class in the namespace. If you want class functions, well, that's what we are talking about here, let's bring back class functions.

I think this addresses everything in your comment? Or do I need to keep on showing counter-points to each and every language on your list?

tasn added a comment.EditedThu, Aug 8, 5:01 AM

Actually, now I'm really pissed off you are wasting my time, here's a fucking C# example:

using System;
					
public class Program
{
	public class A {
		public static void foo() {
			Console.WriteLine("A");
		}
	}
	
	public class B : A {
		public new static void foo() {
			Console.WriteLine("B");
		}
	}

	public static void Main()
	{
		B.foo();
	}
}

There's literally a dedicated keyword in the language for that called "new" (though it also works without but has a different meaning). I'm not sure about the details because I'm not a C# dude.

Or are you referring to more subtle behaviours like calling the new B.foo from within A functions when you override? If so, all of this doesn't matter because the actual inheritance is implemented in C. Heck, it's even something that we talked about in C++ (both @felipealmeida and @cedric were there to name a few), it's a known limitation, C functions can't access overridden functions, but it's not only because of this. It's also the case with normal overrides.

This is overloading not overwriting, you wasted your own time. Please lookup how do do overwrites in c#

tasn added a comment.Thu, Aug 8, 5:21 AM

Read what I said at the bottom of the last post. It doesn't matter because everything is done in C anyway. You don't get the behaviour you're describing in normal non-class functions either. It always behaves like overloading because it calls C directly under the hood, doesn't actually use the language's object system.

Anyhow, I don't care if it's overloading, overwriting and whatever you want to call it. This is the use-case we implemented. This is the usecase that's supported in every language in the world (now you seem to concede), and this is the use-case you broke with what now seems to be no apparent reason (as it works fine in C#).

tasn added a comment.Thu, Aug 8, 5:22 AM

And also you haven't addressed the other point, which is even if you were right about this point, these shouldn't live in the class but rather in a related namespace.

raster added a subscriber: raster.Thu, Aug 8, 5:42 AM

@tasn is right - from the point of view of a user - it's the same. even if c# and java couldn't do it then its a "c only feature" - they can CONSUME it and make use of it from what efl does in C.

@tasn I am talking about the plain difference between what is called a class function in C# and what we before called class function in eo (before my patch).

In C# the static functions are statically dispatched, means:

((Cast to class A)Obj.getClass()).foo()

is not equal to:

((Cast to class B)Obj.getClass()).foo()

Even if obj is of type B, and even if both are called the same.

Before in eo, we did dynamic dispatch:

foo(class_get(obj))

This would always call the same function, the one defined by the type of obj.

The new keyword results in nothing else than you agreeing that this function is new to the class you are implementing it, a class lower in the inheritance just calling Foo() (you don't need to specify the class in there) will call the Foo() of the class it is called in. Not your new one.

Your examples with java and python are still completely valid and work like that in eo (there might be an error about name collisions, but that's something else). The only difference is that you do not need to pass the class anymore...

I feel like we are fighting over something that actually works in eo (beside the maybe name clash)

tasn added a comment.Thu, Aug 8, 6:12 AM

Thanks for adding the clarifications, though this is something I already addressed at the bottom of: https://phab.enlightenment.org/T7675#139789

Yes, I'm familiar with those differences, we knew them when things were made the way they did, though they don't matter! As both @raster and I said above, all the logic is done in C anyway, the implementation detail in C# doesn't matter because it's never utilised.

Or to use your exact same example, in C#, with the Eo bindings:

((Cast to class A)Obj.getClass()).foo()

would be the same as

((Cast to class B)Obj.getClass()).foo()

which is how it's intended given that the object system is not implemented in C#. Are you objecting to this? Are you saying you would like it to explicitly call different one in these cases? Because if you are, I'm sorry but to this standard all of our bindings and all of the Eo interactions are "wrong". For example, doing "super skips" in Python wouldn't work:

class Efl.text extends Efl.Object:
   def foo():  # not a class method and implemented in object

class B extends Efl.Text:
   def foo():
      super(Efl.text).foo() # Will actually call the main Eo function, no super applied

So back to my ad absurdum from the beginning, let's drop inheritance, it doesn't work like the language expects in some cases.

Yes, bindings have limitations, we know that, not everything behaved exactly like every language. It's because you can't. Language have different behaviours, different inheritance models and etc.

So back to the original point: it works just fine in C#, at least from the user's point of view, and it's actually useful. The way it is now it *doesn't* work in C, only in (some?) bindings. Because if you can't pass the class in C, you can't know which implementation of the function to call.
Unless you're suggesting to just create completely different functions, which I think you are (based on the name collisions comment), but that's exactly the opposite of what Eo tries to achieve. We wanted to have a small set of non-redunant functions and you are suggesting to add redundancy for a subset of languages we may (or already) bind to, where I already showed don't actually need it.

Do you see where I'm coming from on this one?

I think you did not understand what the *new* function in C# is doing for static functions. If you use it, it tells you that function, where you declared it is shadowing the definition that is lower in the inheritance structure. Means that by anonymous calling from inside the class, everything inheriting from this class will call the new function. Function calls inside classes we have inherited, are still going to the original definition, not impacted by the *new* API. Which is the behaviour we have right now

So it *is* a new function that gets added.
And no I do not see where you are coming from.

tasn added a comment.Thu, Aug 8, 6:34 AM

Yeah, I understand that new means override (now that we have discussed it further), but as I said, in my last comment and previous ones, it doesn't matter, because this logic is handled by C anyway. The same scenario you just described would break even with non-class functions because the C code will not call your C# code. So I don't see why the obsession with this specific case of class functions when the same functionality is overall broken.

A new function or an old function, it doesn't matter because the bindings will not actually even implement it, so in the bindings (I'm using Python for convenience) it will look like:

class Efl.Text extends Efl.Object:
    pass

Efl.Text.some_object_class_function()  # <-- this will call the correct Efl.Text override even though you didn't do anything in the bindings

Again, it's literally things we spent hours upon hours discussing and ironing out, it's not a new surprise.

It doesn't matter how the C# inheritance works because it's not at play here. As both @raster and I have said earlier, to the user, the behaviour is the same.

The differences do matter quite a lot, if we build up an API in .eo files that relies on this feature (for example, overwrite a API on the class, which is then called from inside efl) then this is not available in C# as this is 1. Not known to C# people 2. Not possible while calling it a class function. ( You can replace C# with any languages I gave you above)

If you think that this feature is required, let's reintroduce it, but maybe call it differently and let's keep calling class functions what class functions are ( not defined by JavaScript)

However, discussing this here for roughly a day, for what do you actually need this specific behaviour ?

tasn added a comment.Thu, Aug 8, 7:03 AM

Marcel, I keep in repeating myself. I already addressed what you just wrote numerous times like at the last paragraph of: https://phab.enlightenment.org/T7675#139789
Even with non-class functions, C functions can't access overridden functions in C# (or if they can there, not in all bindings), and if there's a way to make it work, then there will also be a way to make it work with overrides not just overwrites.

However, discussing this here for roughly a day, for what do you actually need this specific behaviour ?

I explained above. Singleton and factory functions, those are the two examples where this would be used. I think we have (used to have?) factor functions in the efl. At least in elm_window when I converted it, which is I guess why we needed factories in the first place. They became slightly less needed with the addition of constructing properties with eo_add(), because parts of it can also be implemented with those, but they are still useful. Same with singletons
.
However, I'm not saying they are needed (though I believe they are), I would not have objected as much if you just removed them. What I'm objecting here is that now you have class functions in Eolian that are actually not class functions and can't be because of name clashes. So you're stabilising a broken behaviour here.
So either:

  1. Remove them (though I think they are useful, but that can be a different discussion) and implement them as suggested in T8118.
  2. Revert to how they were. I'm not sure how you'd want name them, but even overridden functions are class functions, so I think the name is fine as is.

Factories and singletons are still implemented on various places, and just work normally as in other languages.

tasn added a comment.Thu, Aug 8, 7:48 AM

The problem is with singletons/factories + inheritance, as implied from the context of this discussion.

You can't override the class function (which again, in C you'll get the clash) which means you can't change the factory to return an object of the correct type. It's extra apparent with singletones where if you have:

class A:
    def singleton_get():

class B extends A:
   def singleton_get(): # If this is not allowed

without class inheritance you can't override the singleton it'll just return the singleton of the parent class. Again, you can fix it in the bindings, but the way you currently did it, it won't work in C. This is something I already addressed a few times above.

Do we have a use case? Features are nice, but I think they must be justifiable.

About factories: what is the difference between:

a_singleton_get ();

and

b_singleton_get ();

to

a_singleton (A_CLASS);

and

a_singleton (B_CLASS);

Do we have a use-case where we get the class type dynamically? If we use it statically, this is just syntax-sugar. And not even very sweet since it makes the code bigger.

tasn added a comment.Thu, Aug 8, 1:42 PM

Do we have a use case? Features are nice, but I think they must be justifiable.

Everywhere that uses factories. I'm currently working on the text interfaces, so I easiest to draw from there. There are a few classes that inherit from interface Efl.Canvas.Text_Factory. The factories there override the constructor, because they are not real factories, but if they were, that would be one place.
Efl interfaces is syntax sugar, saying "it's just syntax sugar" really misses the point of all the work that's been going on for the last few years.
As for your example, when you call it a_singleton_get() it's not obvious why it's different, but call it efl_singleton_get() as a master function to get a singleton consistently from any interface and it's obvious why it's better than having efl_text_singleton_get(), efl_image_singleton_get() and a lot of different things. Exactly why we migrated from edje_entry_text_set/evas_object_textblock_text_set/elm_entry_test_set to efl_text_set.

It's not just about being dynamic, it's also about the using just one function. Also (genuinely asking), how much bigger is it actually making anything? And what do you mean by code size? LOC in eo.c? Or significant changes to binary sizes, because if memory serves, it's neither. It uses the same mechanism as eo functions and I don't see why it'd make a difference in binary size.

Though regardless, by the way this discussion is going to: are we OK to admit that class function inheritance in C# is not the reason why this was changed? Given that C++ behaves in exactly the same for all I remember and it works there and has been since day 1? Your input would be beneficial as the guy behind the C++ bindings and I guess also the C# ones?

By size I mean typing more. I'm not against it per se, but for static use it doesn't look like a good tradeoff to me. This is going to uglify bindings and I don't really see much of a difference in change the name of the method or pass a different type. It actually creates one more point for error, where people can pass wrong classes, they can't when the class is embed in the function name.

We would have to add this parameter for all class methods, even ones that are used just for "global" namespacing, like a few @woohyun wanted to have. This parameter is absolutely useless in these cases. But we have to include them because we don't if someone is going to use it dynamically or not.

If people feel strongly they need this, I won't oppose. But, honestly, the only real value I can see is from dynamic use (where you get the class ptr from somewhere else). And I haven't seen a use case for that yet.

Do we have a use-case where we get the class type dynamically? If we use it statically, this is just syntax-sugar. And not even very sweet since it makes the code bigger.

Looking at the code in 3b2a5a429 (before this functionality was stripped from Eo/Eolian):

List of functions marked as @class (from pyolian) and a count of their usage inside src/ (Note that this may include their definition, doc, etc):

  • 30 efl_net_ip_address_parse
  • 23 efl_net_ip_address_resolve
  • 19 efl_net_ip_address_create
  • 11 efl_net_ip_address_create_sockaddr
  • 11 efl_event_global_freeze
  • 9 efl_access_object_event_emit
  • 6 efl_ui_focus_util_focus
  • 6 efl_ui_focus_util_active_manager
  • 5 efl_ui_focus_util_direction_complement
  • 5 efl_access_object_event_handler_add
  • 4 efl_loop_message_handler_get
  • 4 efl_event_global_thaw
  • 3 efl_text_markup_util_text_to_markup
  • 2 efl_text_markup_util_markup_to_text
  • 2 efl_net_dialer_http_date_serialize
  • 2 efl_env_self
  • 2 efl_access_object_event_handler_del
  • 1 efl_net_dialer_http_date_parse
  • 0 elm_obj_sys_notify_singleton_get

Grepping around how they were invoked, each existing invocation was done calling the *_CLASS statically.

In T7675#139812, @tasn wrote:

Though regardless, by the way this discussion is going to: are we OK to admit that class function inheritance in C# is not the reason why this was changed? Given that C++ behaves in exactly the same for all I remember and it works there and has been since day 1? Your input would be beneficial as the guy behind the C++ bindings and I guess also the C# ones?

Given there were no use cases of true dynamic class functions in the API, C# used to support @class statically by providing the *_CLASS pointer hardcoded directly where it invoked C code. And it behaved like a regular C# user would expect from static functions.

Like Felipe said, the main reason to remove was a mix of it seemingly being hard to properly support dynamically and the absence of true dynamic scenarios.

tasn added a comment.Thu, Aug 8, 2:42 PM

By size I mean typing more. I'm not against it per se, but for static use it doesn't look like a good tradeoff to me. This is going to uglify bindings and I don't really see much of a difference in change the name of the method or pass a different type. It actually creates one more point for error, where people can pass wrong classes, they can't when the class is embed in the function name.

You are essentially arguing against efl interfaces here and are creating significant inconsistency. Following your logic we should go back to elm_entry_text_set because now people can pass a different type of object too (while if we had elm_entry_text_set we would get compile time checking). I'm not even arguing if you are right or wrong here, I'm just arguing against choosing this random specific case to be different to how Eo and eolian behave.

As for uglifying bindings: the bindings already had it. This change removed it from the bindings so it was code that was already there and already working (at least for C++). Though I don't see how it uglifies anything, it's literally just another function to generate that calls to an eo function, how is it any different?

The ones just for global namespacing is only addressed by proposal T8118 if I understand you correctly. Something I already proposed before I discovered this change (and actually how I got here).

If people feel strongly they need this, I won't oppose. But, honestly, the only real value I can see is from dynamic use (where you get the class ptr from somewhere else). And I haven't seen a use case for that yet.

I disagree I think the syntax inconsistency is a major one too. I think an example for this could also be found, but really, the inconsistency with the rest of Eo is enough.

You are literally telling users to use efl_text_set everywhere, oh except for this one special case where it doesn't work, and again, for no good reason.

I'll let other people chime in. If nobody else opposes, then IMO you can go ahead and reinclude it. If that happens, then we need a solution for T8118 first, IMO.

tasn added a comment.Thu, Aug 8, 2:50 PM

@lauromoura: I think I already addressed your comment too in my reply to @felipealmeida , please let me know if that's not the case.

Just one addition: I think judging based on current usage is unfair when really people were scrambling to even migrate to the Eo API in general, so definitely no one had time to explore new functionalities, and not to mention new design. And I'm tell you that as someone that actually did a lot of that work. It's also a bit narrow minded to limit our infrastructure based on what's there and not what can be.

Though as I said, I'm not strictly against removing class functions if people don't find them useful (that's a different argument though), what I'm arguing is that what there is now is wrong. Either remove them and do like T8118 or restore them. Removing them at least gives up the possibility to add them again in the future if we think they are needed (though I think they should already be part of our infrastructure).
To build on this argument, there's a reason why class functions and the new operator exist in C# and all other languages, it's because they are useful. :)

In T7675#139819, @tasn wrote:

@lauromoura: I think I already addressed your comment too in my reply to @felipealmeida , please let me know if that's not the case.

Do you mean the Text_Factory classes? I'm wondering what would be the case for them to have actual @class dynamicity.

Though as I said, I'm not strictly against removing class functions if people don't find them useful (that's a different argument though), what I'm arguing is that what there is now is wrong. Either remove them and do like T8118 or restore them. Removing them at least gives up the possibility to add them again in the future if we think they are needed (though I think they should already be part of our infrastructure).

Would it be a reasonable compromise to borrow the @static modifier from Python and use it alongside @class?

  • @static - Plain functions, just namespaced inside the given class.
    • Would replace current usage of @class
    • Behaves like regular C++/C# static methods too
    • Overloadable, but not overrideable
    • Probably replaces/complement T8118
  • @class - "Old style" @class methods. Would receive the class pointer as the first argument.
    • Would be reintroduced only if we reach some kind of consensus regarding the tradeoffs between their usefulness and feasibility/integration with target languages?

To build on this argument, there's a reason why class functions and the new operator exist in C# and all other languages, it's because they are useful. :)

Sure. But static methods in C# are actually more like what we have now, "namespaced functions" than actual "class functions", aren't they?

tasn added a comment.Fri, Aug 9, 12:44 AM

Do you mean the Text_Factory classes? I'm wondering what would be the case for them to have actual @class dynamicity.

I didn't say dynamically, I said @class functions that would be overridden.

Would it be a reasonable compromise to borrow the @static modifier from Python and use it alongside @class?

@static sounds like a good solution for T8118, but what's the advantage over just "floating"? Compatibility with languages that don't allow floating functions? How does C# handle "floating" structs btw? Do they have to be in a class too or is it OK to have them floating?

In T7675#139845, @tasn wrote:

Would it be a reasonable compromise to borrow the @static modifier from Python and use it alongside @class?

@static sounds like a good solution for T8118, but what's the advantage over just "floating"? Compatibility with languages that don't allow floating functions? How does C# handle "floating" structs btw? Do they have to be in a class too or is it OK to have them floating?

Yeah, C# allows top level structs (alongside enums, classes and delegates (aka function pointers)). Actually, things that define a type.

tasn added a subscriber: q66.Fri, Aug 9, 8:42 AM

Gotcha, good to know. Then @static is maybe the best option for T8118. @q66, anything to contribute regarding the syntax suggestions?

q66 added a comment.Fri, Aug 9, 8:57 AM

If it's just renaming to @static, then that's fine and easy

tasn added a comment.Fri, Aug 9, 9:21 AM

It's adding back @class and then adding @static that is just like what @class is now. OK, thanks for the feedback!

q66 added a comment.Fri, Aug 9, 9:27 AM

Hm? why not just rename current @class to @static (which is easy and quick) and then only re-add @class later if it ends up being needed?

tasn added a comment.Fri, Aug 9, 10:06 AM

That's one of the suggestions I made above. I'm fine with that too, though that's a different discussion.

It's not just that, you also need to make sure that static is only allowed on classes and not interfaces, and you can only implement where it was defined, not elsewhere.

In T7675#139861, @tasn wrote:

It's not just that, you also need to make sure that static is only allowed on classes and not interfaces, and you can only implement where it was defined, not elsewhere.

Why remove it from interfaces? It is pretty useful there and has it is just a static function with a prefix, why would we need to disable it for interfaces? It does enable things like D9604 .