Optional interface methods

Monkey Forums/Monkey Programming/Optional interface methods

Samah(Posted 2014) [#1]
Mark,
Have you put any more thought toward this?
http://monkey-x.com/Community/posts.php?topic=6160&post=70800
I think it'd be a great enhancement. If it were provided as a pull request, would you consider it?

Samah


Shinkiro1(Posted 2014) [#2]
I have just recently really started to appreciate interfaces and the possibility of them being optional.
The OSX Cocoa library makes heavy use of this.

The thing is we will have to know if a class that implemented an interface has also implemented a certain method (one which is optional).
In Objective C there is method called 'respondsToSelector: @selector(methodName)'.
That means monkey would need treat methods like objects, or using reflection which I think is too much overhead.

PS: Samah, have you already implemented this yourself (because you ask for pr)?


marksibly(Posted 2014) [#3]
I have no plans to change this right now.

You can easily work around any problems by providing abstract versions of the interface methods - eg: http://stackoverflow.com/questions/2705163/c-abstract-classes-need-to-implement-interfaces - so I don't consider it inhibits what you can actually do with the language. It's not 'wrong', just 'different', ala c#!

I would consider a pull request, but make sure that:

* It works with ALL target languages.

* It handles ALL weird/silly corner cases.

* It's written in the same 'style' as existing compiler code.


Samah(Posted 2014) [#4]
Just for clarification, the enhancement request is similar to optional methods in Objective-C protocols.
Example from Cocoa:
// protocol in Objective-C is similar to interface in Monkey
@protocol UITableViewDataSource<NSObject>
@required
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
@optional
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView;
// ...
@end

So when you define your Objective-C class that implements the protocol, only those two required methods MUST exist. The optional ones will have dummy implementations generated by the compiler.

Possible Monkey example:
Interface Test
	Method Hello:Void()
	Method World:Void()
	Method Foo:Void() Optional
	Method Bar:Int() Optional
End

Class MyClass Implements Test
	' Hello must be implemented
	Method Hello:Void()
		Print "hello"
	End
	
	' World must be implemented
	Method World:Void()
		Print "world"
	End
End

' final class looks like this internally
Class MyClass Implements Test
	' already implemented
	Method Hello:Void()
		Print "hello"
	End
	
	' already implemented
	Method World:Void()
		Print "world"
	End
	
	' autogenerated before compilation
	Method Foo:Void()
		' do nothing
	End
	
	' autogenerated before compilation
	Method Bar:Int()
		' return default value for Int
		Return 0
	End
End

This could all be done in trans automatically; it would have nothing to do with the target languages.


Markus(Posted 2014) [#5]
what you mean with internally is invisible code. i don't like.
its better to generate that with a automatic by shortcut or anything in source code.
and then you do not need the "optional" it is just a dummy function there.


Shinkiro1(Posted 2014) [#6]
@Samah: When I talked about Cocoa I had exactly this protocol in mind xD

@Markus: The whole point of optional would be that you don't have to implement the method that is marked as such in the interface.


Markus(Posted 2014) [#7]
@Shinkiro1
i think it make more sense to split in two interfaces
Interface Test
Method Hello:Void()
Method World:Void()
End
Interface TestOptional
Method Foo:Void()
Method Bar:Int()
End
Class MyClass1 Implements Test
Class MyClass2 Implements Test,TestOptional


Shinkiro1(Posted 2014) [#8]
What if you only need 1 Method of TestOptional ...
1 Interface per Method?


Samah(Posted 2014) [#9]
@Markus: its better to generate that with a automatic by shortcut or anything in source code.

What if I use a different IDE that doesn't support code generation shortcuts?
@Shinkiro1: The whole point of optional would be that you don't have to implement the method that is marked as such in the interface.

Exactly, and if you can easily add a keyword to save yourself typing and to make your code much clearer, why not?
I still don't understand why there's no automatic code generation for properties, like in C# and Objective-C. Again, this can just be internal to trans; no changes necessary to target code.


marksibly(Posted 2014) [#10]
Hmmm, okay, I thought you were just talking about 'fixing' some the interface compatibility issues...

Interesting idea...my first response is that any 'auto generated' optional methods should probably throw a runtime error, not just return a default value, ie:

Class MyClass Implements Test
	' already implemented
	Method Hello:Void()
		Print "hello"
	End
	
	' already implemented
	Method World:Void()
		Print "world"
	End
	
	' autogenerated before compilation
	Method Foo:Void()
		Error "Optional method cannot be called"   'or maybe throw something...
	End
	
	' autogenerated before compilation
	Method Bar:Int()
		Error "Optional method cannot be called"
	End
End


Googling around...this is what Java collections apparently does, and it makes more sense to me than having an unimplemented method magically 'do something'. More on the topic of optional methods in Java collections here - see esp. the 'big answer'.

http://stackoverflow.com/questions/10572643/optional-methods-in-java-interface

Also, I can't help but agree with the idea that finer grained interfaces are probably a better approach/goal - if an interface doesn't provide support for all it's operations, it's not much of an interface!

it's kind of different in ObjectiveC, because you can query for method support at runtime - this is kind of the equivalent of using finer grained interfaces and downcasting at runtime to see what's supported.

If the goal is purely just to save some typing, then...?

All in all, not sure what I think of this just yet...


Samah(Posted 2014) [#11]
Googling around...this is what Java collections apparently does, and it makes more sense to me than having an unimplemented method magically 'do something'. More on the topic of optional methods in Java collections here - see esp. the 'big answer'.
http://stackoverflow.com/questions/10572643/optional-methods-in-java-interface

Did you read the second answer (that's not accepted)? It says in bold "There are no exceptions to this rule". To the compiler, Collection is a normal interface with all methods being mandatory. The difference is that each collection type has an abstract class that (by default) denies the usage of those methods that are considered "optional" for that collection type.

Really, the point of optional methods is to save you from making an abstract class as the Collections package does. Interfaces are a way of faking multiple inheritance, but requiring the developer to define the functionality of every method. Having optional methods allows you to write less code to do the same thing, and makes it look much cleaner. Basically you can get all of the benefits of interfaces, with some of the benefits of abstract classes.

If the goal is purely just to save some typing

Then why do we have the Property keyword if it just converts () to = ?

Edit:
If you're worried about changing the way interfaces work, maybe create a new type called Protocol that does exactly the same thing but with optional methods? That way everyone's happy. :)

Edit 2:
Java 8 supports default methods.


marksibly(Posted 2014) [#12]
Well, I'm just more confused now...

I still don't like the idea of 'auto generated' optional methods returning a value - I can only see this leading to very confusing bugs if someone forgets to implement an 'optional' method that is necessary for an interface to be useful. I'm a little less wary about auto generated methods throwing an exception, but still, it seems to go against the whole idea of interfaces. I guess it's effectively like allowing people to create an instance of an abstract class, where abstract methods either return null, or throw an exception or whatever.

Back to what I *thought* you were meaning at the start of the topic:


Interface Fluffy
Method BeanBag:Void()
End

Class TiddlyWinks Implements Fluffy Abstract
End


IMO, this *should* build - the compiler could insert a 'Method BeanBag:Void() Abstract' into TiddlyWinks to shut up C#, and any class that extended TiddlyWinks would be forced to implement BeanBag (this is probably what Java does?). If I had infinite time, I'd probably do the necessary grunt work but IMO it's just not that big a deal.

But you've confused me with all this talk about an 'Optional' keyword etc.


marksibly(Posted 2014) [#13]
> Java 8 supports default methods.

That looks a look healthier to me - instead of optional methods doing 'something compiler defined', the coder gets to choose what they do.

I believe this is very close to what's referred to as a 'mixin'.

Now, all we need is fields in interfaces...


Samah(Posted 2014) [#14]
Back to what I *thought* you were meaning at the start of the topic:

Yeah, that's something that's annoyed me for a while, but the workaround isn't too much of a pain.

That looks a look healthier to me - instead of optional methods doing 'something compiler defined', the coder gets to choose what they do.

Does that mean you'll look at adding it? :D <3

Now, all we need is fields in interfaces...

I know, right... :(


Markus(Posted 2014) [#15]
the idea of interfaces is that you want have ALL the function in the class you include this interface.
means load/save/write log.

the way you want is a class with methods, this class you can include in other class but you can overwrite the methods
with your own ones etc. means some possibilities like .net c# .
i believe c# have also the feature must overwrite/override.


therevills(Posted 2014) [#16]
the idea of interfaces is that you want have ALL the function in the class you include this interface.

Not necessary, if you check out Java's Mouse Listener interface:
http://docs.oracle.com/javase/7/docs/api/java/awt/event/MouseListener.html
You would have to implement all the methods even though you might only use one or two. So your code ends up like this:
public class MouseListenerTest extends JFrame implements MouseListener
{
     private JTextArea exitText;
     private JTextArea printText;

     public MouseListenerTest()
     {
          super("Test");

          JPanel p = new JPanel();

          exitText = new JTextArea(2, 10);
          exitText.setText("Click me to exit");
          exitText.addMouseListener(this);

          printText = new JTextArea(2, 10);
          printText.setText("Click me to print \"Hello\"");
          printText.addMouseListener(this); 

          p.add(exitText);
          p.add(printText);

          getContentPane().add(p);

          setVisible(true);
     }
     
     public static void main(String[] args)
     {
          new MouseListenerTest();
     }

     public void mouseClicked(MouseEvent e)
     {
          JTextArea temp = (JTextArea) e.getSource();
          if(temp.equals(exitText))          
               System.exit(0);
          else if(temp.equals(printText))
               System.out.println("Hello");
     }
     
     public void mouseEntered(MouseEvent e)
     {
     }
     
     public void mouseExited(MouseEvent e)
     {
     }

     public void mousePressed(MouseEvent e)
     {
     }

     public void mouseReleased(MouseEvent e)
     {
     }
}


If the methods where optional it would look like this:
public class MouseListenerTest extends JFrame implements MouseListener
{
     private JTextArea exitText;
     private JTextArea printText;

     public MouseListenerTest()
     {
          super("Test");

          JPanel p = new JPanel();

          exitText = new JTextArea(2, 10);
          exitText.setText("Click me to exit");
          exitText.addMouseListener(this);

          printText = new JTextArea(2, 10);
          printText.setText("Click me to print \"Hello\"");
          printText.addMouseListener(this); 

          p.add(exitText);
          p.add(printText);

          getContentPane().add(p);

          setVisible(true);
     }
     
     public static void main(String[] args)
     {
          new MouseListenerTest();
     }

     public void mouseClicked(MouseEvent e)
     {
          JTextArea temp = (JTextArea) e.getSource();
          if(temp.equals(exitText))          
               System.exit(0);
          else if(temp.equals(printText))
               System.out.println("Hello");
     }
}


Which is a lot tidier, cleaner and easier to read.


Nobuyuki(Posted 2014) [#17]
I dunno if there's a necessity for this, after thinking about it for a while. The bigger the interface gets, the more it requires a critical look at what exactly it's providing an interface for, and what is actually required of that interface vs. what can be factored out into multiple interfaces. Maybe it's a style as well as a convenience question as to whether you want a single interface to exhibit a high degree of polymorphism, and what this does for the safety of its implementation. Maybe I'm just tired. But, it's been my experience that any time I've written something as an interface that starts to get too huge, I start looking at the topology of potential implementing classes and find out that I probably should've been doing either one of two things:

1. Using an abstract base class for most of the major functionality, and maybe a couple of interfaces to work around some basic interactions with other, mostly-unrelated classes.
2. Splitting the interface up into smaller pieces so that the interfaces' usage can be applied more fittingly to the classes that would be implementing some (or all) of them.


Samah(Posted 2014) [#18]
@Markus:
In Monkey (as in Java) all methods are non-final by default. If you want to force the developer to override/implement it, you define the method as abstract.

@Nobuyuki:
1. Except as soon as you bring in an abstract class, you're losing the quasi-multiple-inheritance benefits of interfaces; you start encroaching on the class hierarchy for your data structures.
2. As therevills has shown, the Listener pattern is one that greatly benefits from optional methods. It's possible that your listener will want to handle many kinds of events to do with the same source. A good example is mouse, keyboard, and joystick input. Those should be three separate interfaces, but each interface might have a lot of possible operations. If you only care about mouse clicks, you shouldn't have to put in dummy implementations for mouse movements, etc.


Markus(Posted 2014) [#19]
@therevills
i know, but it make no sense or would be inconsequent if you write a load method but the save is optional or only a dummy.

@Samah
whatever.
about the listener example, i would use 3 input classes for keyboard/mouse/gamepad and one universal interface for my app.
means left can be the cursor key at keyboard,moved mouse at left,or moved stick left.
or button 1 is enter or space/left mouse button or joy button. no method is optional.


Nobuyuki(Posted 2014) [#20]
@Samah
Abstracts are for class hierarchies that shouldn't be using interfaces for so many methods. If you need greater MI than that, that's what my option 2 is pointing towards. The interface should be split up according to the hierarchy of its most common usage pattern(s). That is to say, listeners should implement more basic interfaces down to an atomic operation, if necessary. If it's not, you can group them together. If neither way works, What I'm saying is that you're probably not going about it the right way, or your interface/class structure has become unmanageable.

I can't see how this isn't true from the example given -- it's a lot harder for them to refactor Java than it is for us to refactor our stuff. Optional methods in an interface seem lazy (I thought the same thing about optional arguments, but they are convenient and definitely harder to abuse than in VB), and like I said, optional methods don't seem to guarantee their safety in the same way as the current system as far as I can tell and might in fact limit their usage without that guarantee.


Samah(Posted 2014) [#21]
@Markus
Whatever.

@Nobuyuki
We can argue OO-patterns forever, but in the end it really comes down to which one works best for the situation. If features like optional methods make a pattern shine, you can't really poopoo it just because it's useless for others.

Anyway, Mark has stated that he has no plans to add optional interface methods. He has however shown interest in developer-defined default implementations. Let's wait and see what his response is.