Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proposal: insist on static members in an interface #3734

Closed
darrenoakey opened this issue Jul 27, 2020 · 8 comments
Closed

proposal: insist on static members in an interface #3734

darrenoakey opened this issue Jul 27, 2020 · 8 comments

Comments

@darrenoakey
Copy link

darrenoakey commented Jul 27, 2020

it seems wrong that an interface can force a set of instance members, but not static members. There are all sorts of times where you want do do polymorphic instantiation of objects that implement an interface, and it seems strange that you can't say - "and it must be deserializable from a string" for instance..

eg:

       public interface GraphicsFileFormat<T> : GraphicsFileFormat where T : GraphicsFileFormat<T>
       {
            ...
              static boolean Matches( string filename );
              static T CreateFrom( string filename );
       }
      ...

      private static readonly allTypes = ReflectionSimple.AllTypesThatImplement<GraphicsFileFormat>();
      ...    
  
      public GraphicsFileFormat Load( string filename )
      {
            var format = allTypes.First( x => (boolean) ReflectionSimple.CallStatic( x, nameof( GraphicsFileFormat.Matches), filename ));
            return (GraphicsFileFormat) ReflectionSimple.CallStatic( x, nameof( GraphicsFileFormat.CreateFrom), filename );
      }

so - being able to do so - ie create static functions inside of an interface that say "whoever implements this must also have this static function" - would make a lot of things a lot cleaner. At the moment, most people solve this by having an empty constructor and then some "initialise" type function on the interface - which is completely horrible in the new "all objects are immutable" world we seem to be rapidly approaching.

@canton7
Copy link

canton7 commented Jul 27, 2020

I don't think interfaces are intended to exist purely to support reflection. This is a feature which would only be useful to reflection, since you wouldn't be able to call the static method given an instance of the interface.

Look at the Shapes proposal (#164, #2528, etc) -- they solve the same issue but in a way which is useful to non-reflection-based code.

@darrenoakey
Copy link
Author

interesting - the only comment I'd make is that shape seems like a big change that's going to take a while - the above change is little more than a validation - it really has no larger effects and won't break anything - so I'd imagine it could be implemented quite easily?

@canton7
Copy link

canton7 commented Jul 27, 2020

It wouldn't do anything though - you can't dispatch to the static method through the interface, you have to use reflection. I doubt a language feature which only impacts reflection is going to have much priority. You'd be better off with a language feature which removes the need to use reflection here at all, which is what Shapes will do.

@333fred
Copy link
Member

333fred commented Jul 27, 2020

We talked about this very issue in LDM several weeks ago: https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-06-29.md#discussion.

@333fred
Copy link
Member

333fred commented Jul 27, 2020

And yes, we're absolutely more interested in non-reflection scenarios. We'd much rather make the language easier to use while continuing to be type safe, rather then enabling more reflection scenarios that can't be done safely. If this is a constraint you want, I'd suggest an analyzer. Mark an interface with an attribute, and then flag any implementation that does not have the static member you expect.

@darrenoakey
Copy link
Author

darrenoakey commented Jul 28, 2020

@333fred

I know what you are saying - but for me - it's less about constraining and more about producing... I very much believe in building libraries that are impossible to get wrong for the user - I reckon it's the right choice to shovel basically any amount of "hack" under the covers if it makes it even slightly simpler/cleaner for the user.

And the bottom line here, is that if you as a user are using something like resharper - you go to pass X into something that takes interface Y - you get a squiggly line that says "x doesn't implement y" - without taking your hands away from the keyboard or moving your focus you hit alt-enter - then enter to make X implement y, and get a bunch of stubs that throw notimplementedexception - you run your tests, stuff goes bang.. you fix it.. it's done... It's "zero thought" development :)

and the problem is... no one tells you you needed to create a factory method of this shape. There's no way to embed that concept in the code. I couldn't care less how it gets used - I just want a way of telling the person using my code - "this is something you need to do" - and putting it on the interface, which already is just a list of things they need to do, is completely logical and consistent.

@333fred
Copy link
Member

333fred commented Jul 28, 2020

and the problem is... no one tells you you needed to create a factory method of this shape. There's no way to embed that concept in the code. I couldn't care less how it gets used - I just want a way of telling the person using my code - "this is something you need to do" - and putting it on the interface, which already is just a list of things they need to do, is completely logical and consistent.

Sure there is. An analyzer would be perfectly capable of doing that. You create a RequiredStaticMethodAttribute that models a static method signature, or you could even just write the static method and put the attribute on it directly.

And the bottom line here, is that if you as a user are using something like resharper - you go to pass X into something that takes interface Y - you get a squiggly line that says "x doesn't implement y" - without taking your hands away from the keyboard or moving your focus you hit alt-enter - then enter to make X implement y, and get a bunch of stubs that throw notimplementedexception - you run your tests, stuff goes bang.. you fix it.. it's done... It's "zero thought" development :)

Analyzers can provide fixers as well, which would be quite capable of achieving zero-thought development.

@YairHalberstadt
Copy link
Contributor

Closing as discussed as part of #164 and #1711

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants