7 ms·
Dynamic languages like JS, Ruby and Python could greatly benefit from explicit support for interfaces as well. I'm enjoying the fact that Clojure brings this po
by swannodette 16y ago
Dynamic languages like JS, Ruby and Python could greatly benefit from explicit support for interfaces as well. I'm enjoying the fact that Clojure brings this powerful abstraction to a dynamically typed language.
- j_baker 16y agoPython has interfaces. There isn't even a need for it to be supported by the language. I don't see why Ruby or JS couldn't support them as well. http://pypi.python.org/pypi/zope.interface http://pypi.python.org/pypi/zope.interface http://docs.python.org/library/abc.html http://docs.python.org/library/abc.html
- jamesbritt 16y agoCan you give an example of where one would want to use an interface or an abstract base class in a dynamic duck-typed language? I looked quickly at pep-3119 and it seems like it's a short-hand way of checking if an object will respond to some set of methods. Now, I cop to having done type checking in Ruby (either with is_a? or respond_to?) but I always felt it was a code smell, a hack to solve a distraction while I moved on to something else more pressing. I don't know a whole lot of Python, but I'm guessing that since Python has a more Java-like form of OOP (i.e., method invocation vs. the message passing of Ruby, a la Smalltalk) this kind of type-checking is quite acceptable, even though Python is ostensibly duck-typed. Am I wrong, and by how much?
- patio11 16y agoAbout the only thing I use is_a? for routinely in Ruby code is to allow a particular function to accept many types of things as arguments. (An array? Sure! A single object? Why not? A single ActiveRecord id? Don't sweat it, I can do .find(id), too!)
- aeden 16y agoYou could even do away with is_a? there and just ask if the argument responds_to a particular method and then call the method if it does. I find myself doing more of this and less of calls to is_a? these days.
- steveklabnik 16y agoIt's conceptually much cleaner, too. If you're asking about the type of something, you're almost always just trying to see if it has some method. Just ask about the method response directly.
- j_baker 16y agoOstensibly, Python has a more Java-like model of method invocation, but this is really only a semantic difference. There is little that you can do with Python methods that you can't do with Ruby's methods and vice-versa. Generally, checking the type with isinstance is considered bad practice although it can be useful sometimes (I can't think of any simple examples off the top of my head though). The main reason I can think of for using an interface or abc is simply so that if you forget to add a required method, the exception gets thrown sooner rather than later. Plus with an abc, you also allow the base class to define methods that depend upon abstract methods (for instance, if you subclass the Mapping abc, you get __contains__, keys, items, etc for adding __getitem__). Strictly speaking, there's no reason why you can't do that without an abstract base class, but it makes it easier. In short, there are useful reasons to have interfaces and abstract base classes in Python, but they probably aren't the same reasons you'd want them in a statically-typed language like Java.
- thristian 16y agoTwisted, the Python networking framework, makes extensive use of interfaces in its API. The "Interfaces and Adapters" chapter in the documentation goes in to some detail about why you would want such a thing: http://twistedmatrix.com/documents/current/core/howto/components.html http://twistedmatrix.com/documents/current/core/howto/compon... If you're in a hurry, the main motivations appear to be: - declaring that a class supports particular functionality without risking the complications of multiple inheritance - the ability to register adapters from one interface to another means no more calls to isinstance() (or at least, they're abstracted away to a library function) - Easy to make your test suite check that you haven't forgotten to implement any methods of any of the interfaces your class claims to support.
- rdtsc 16y ago"I want to say one word to you. Just one word." -- Plugins ;-) You can pick out a set of objects that implement a certain interface from a larger set. You can do this for classes, objects, perhaps modules. Someone already mentioned Twisted plugins. They currently use Zope interfaces. You create a class then declare that it implements a particular interfaces.
- swannodette 16y agoThere's a difference between having a language feature (or it's possibility) and actively encouraging it. Far too many classes are bag of a implementation details with no thought for a design. In Clojure you can't just declare methods willy-nilly. You must implement methods that are a part of protocol (interface). This encourages two things, a) interoperability and b) the creation of new reusable designs- implementations rightfully take the backseat. Haskell type classes seem, to me, to take the right approach here as well. In fact I would argue their main benefit is not catching programmer error - but encouraging thoughtful design.
- russellperry 16y agoBy this logic every language should have C-style headers. There's nothing to prevent me from creating a bloated API/interface with or without the framework forcing me to declare it external to the class, in interfaces, headers or otherwise. In Eclipse it's as simple as using the refactor tool to 'pull up interface' from any God Class of my choosing. Neither language nor framework can force a coder to apply the Single Responsibility Principle. Coders can be willy-nilly with or without interfaces.
- SpikeGronim 16y agoI'm curious why you want interfaces in languages with duck typing.
- swannodette 16y agoBecause it allows programmers to define a minimum contract for behavior. Instead of having to subclass (and being implicated into a hierarchy) you can instead provide any object as long as it satisfies that interface.
- russellperry 16y agoAllowing a class-level contract would fundamentally alter the dynamic nature of a language like Ruby. It might be cool (although I personally don't see the benefit), but it wouldn't be Ruby. What mechanism would enforce the contract anyway? The best you could hope for would be a runtime error thrown when the interpreter detected the incompatibility, and you can do that manually now (I do it frequently to imitate abstract classes).
- rapind 16y agoclass IAnimal def growl raise end end
- russellperry 16y agoYeah exactly! 'raise "not implemented"' is how I imitate abstract classes (on the rare occasion that I need them).
- wrs 16y agoAren't interfaces essentially a reification of duck typing? If it implements the duck interface, it's a duck. So the reason you'd want it is just to have a conventional way to define what a duck is, and ask if an object was one. (And you could probably implement this in about three lines of Ruby.) Now, many languages with formal interfaces (e.g., Java) are strongly typed, and they treat interfaces as types. Thus, for example, classes have to declare up front what interfaces they implement. That doesn't fit well with the flexible attitude of a duck-typed language. However, if interfaces were just collections of method signatures that could be tested against objects at runtime, that would be perfectly compatible with duck typing. Languages like Modula-3 that use structural type equivalence sort of do this even in a strongly-typed system. Sort of.
- russellperry 16y agoThis might make sense for Clojure (I haven't used it) but in my years of Ruby programming (after 10 years in Java and C#) I have never thought to myself, man I'd love to have an interface here. Ruby's lack of class-level contracts is essential to its idiomatic nature, a strength not a weakness, imo.
- gregwebs 16y agoGenerally speaking I like interfaces, but Ruby is so dynamic that you couldn't use them for compile-time guarantees. Interfaces could only get you a slightly nicer way of dynamic duck typing. I wouldn't really call all of the dynamism a strength though - one of the limiting factors of compile time evaluation here is that a method can later become undefined- when is the last time you needed that?
- steveklabnik 16y agoActually, undefining methods on an object because such an idiom that Ruby 1.9 introduced a new base class into the hierarchy: BasicObject. [1] This is now the new root class, above Object. 1: http://www.ruby-doc.org/core-1.9/classes/BasicObject.html http://www.ruby-doc.org/core-1.9/classes/BasicObject.html
- gregwebs 16y agoYeah, that is the 1 case, and ActiveSupport has had a BasicObject for a while now. This is another case where proponents would say it is great that you can undefine a method, but I would say that is a hack for lack of any namespace management. Now that there is a BasicObject I am not sure that there is any practical use for undefining a method- probably only for dealing with namespace collisions, which again seems to point out a language flaw, not a feature of dynamism.
- swannodette 16y agoThis is short-sighted. The key point in your statement is "I". Contracts are not about "I". They are about everyone else. You have a great design and interfaces allow you to share that.
- tres 16y agoSeems to me that Ruby modules affect the same outcome as an interface without all the overhead. Just include the module & you've got the desired behaviors and data types without all the fuss. You get exactly the same benefits as you would from an interface (minus the rigidity)...
- okaramian 16y agoI've been working in C#/.NET for a while and I've started using Ruby recently for a couple of different projects at home. It's messing with my head because I'm starting to kind of hate the rigidity I'm forced to work with when I'm deciding whether I should/should not implement an interface. That said, yes, Ruby with interfaces seems kind of pointless and is just throwing more code in, which is the opposite of one of the nicer points of the language.
- swannodette 16y agoMissing the point entirely. I don't want your module. I want/like your design and I want to provide my own implementation.
- clyfe 16y agoOverride the functions in my module with your own
- jules 16y agoDefine exception throwing "not implemented" methods in the module.
- russellperry 16y agoI get what you're saying, but Ruby already allows you to do this. If you like an API/design, then go ahead and reimplement it however you like. There are no class-level contracts anywhere in Ruby that would prevent this, and therefore interfaces provide no additional level of abstraction that Ruby doesn't already have.