why interfaces in dynamic/loosely-typed languages?
Asked Answered
S

4

7

I work in php, and the concept of interfaces seems to me a little useless here. From reading, I understand that interfaces are part of "design by contract", but without at least guaranteeing a return of a type of a particular kind, there really isn't any contract. It seems it's like a contract that reads, "We agree to do the following: '' " -- there are no terms of the agreement.

If I want a guarantee that an object has a method, it doesn't seem like interfaces are particularly useful. If I try to call a method that an object doesn't have, I get a Fatal Error, so I find out pretty quickly that that class doesn't have a method with that name. If I want to be smart and check beforehand whether a class has a method, then checking the interface, and seeing whether the object implements that interface doesn't seem to save me any more time than just checking that object directly ( which I would do anyways to see if the class had that method regardless of any interfaces it did or didn't implement).

In other words, just because I have a set of methods that have particular names, that doesn't guarantee me any particular behavior. If I'm guaranteed a return of a variable of a certain type, I at least have some inkling of what the output would be, and I can write code that uses an object with that interface, because I know what I'm getting out of it. If it returns a string, I can continue coding with at least the certainty that I'm dealing with a string output afterward. So I'm guaranteed at least some behavior when a return type is specified. Is guaranteeing behavior part of what interfaces are for, or no?

The only thing I can think of is that when I'm writing code, it serves as a post-it note to myself to be sure to create certain methods when writing that class later on. It seems more like scaffolding for when I'm writing the code; I don't see much benefit from when I'm actually using it. So it's more for me to keep the standard when I'm creating classes than when I'm writing them. This benefit doesn't really seem to be captured in the concept of design by contract.

What benefit(s) do you actually get from using an interface in dynamic/loose-typed languages like PHP? Are they great, or is it something that more robust OO languages implement, so PHP implements it also?

Safelight answered 25/8, 2010 at 16:23 Comment(8)
Pedantic note: PHP is not Untyped. It's dynamic and loose typed. There's a HUGE difference...Caramelize
That's not so pedantic if it makes a huge difference :) Fixed.Safelight
What if your software requires that a method returns a prime number or a US-ASCII string? Just because an interface cannot specify that part of the "contract", and those things can throw your program off, does that mean interfaces are completely useless in all languages? Also, in strongly-typed languages, a type-mismatch produces an error as well. So you could just as easily ask why you need to specify a return type in your interface in strongly typed languages.Sophi
Well, it is a huge difference, but I'm not sure it changes the sentiment or answers to your question... Which is why I said pedantic...Caramelize
sounds rather like rant than a questionVariscite
Lèse majesté: "What if your software requires that a method returns a prime number or a US-ASCII string?" - there are efforts in languages and/or tools that let you specify those pre/post conditions.Stocky
@Variscite There are obviously rant elements here, but they don't negate the questions, IMHO ;)Safelight
@Lèsemajesté "What if your software requires that a method returns a prime number or a US-ASCII string?" You would create a class that can only store those value types and require that objects of that type are returned, very simple.Sowens
D
3

Interfaces are used when you actually expect an object to implement a method.

For example, if I'm building a DB wrapper and it supports behaviours, which you register yourself in a bootstrap, then before running your behaviours (for example, sluggable), I will check that they implement my "DB_Wrapper_Behaviour_Interface" by using:

if(!($behaviourObject instanceof DB_Wrapper_Behaviour_Interface)) {
    throw new Exception("Your behaviour doesn't implement my interface");
}
Dysphoria answered 25/8, 2010 at 16:28 Comment(16)
user151841 already picked this aspect up in the question. Can you please elaborate on the usefulness in regards to the doubts raised in the question?Stocky
More than just a method. A method signature. Including types hints and defaults...Caramelize
VolkerK, from both OP and greg0ire I'm getting the feeling they are using interfaces on one-man projects. While this is encouraged, interfaces will start making sense when inter-developer assumptions come into play, like my DB Wrapper - behaviour example.Defrost
@Andrei Yeah, but what does it get you in the big picture? If my class has a method named 'sluggable', and there's no guarantee for what it actually does, why use that functionality? Why not just use function_exists in that case? All your doing is making sure that a method of a particular name exists. That method could do nothing at all, or something completely other than what you expect it to do. What use is interfaces, then, in this case?Safelight
@user151841: Well, what language does an interface enforce the functionality of a method? At most, they inforce input and output types, and exceptions thrown. That's really about it. What happens under the hood is black boxed (and that's the true benefit of the interface, is that you don't care how it does what it does). You could make an iterator where current() returns the inverse of the next variable. The interface would be correct, but the implementation would be "not what was expected", but that's also not what interfaces are designed to enforce...Caramelize
@maxwell At least in a language where a return type is guaranteed, there is some ( perhaps small ) guarantee of behavior. If it returns a string, I can continue to write my code with the knowledge that I'm dealing with a string output, at a minimum. The usefulness of that may be debated in its own question :) However, with dynamic languages, there seems to be almost no benefit whatsoever... am I off-base here? If there's no enforcement of input and output, are they of any use? If I just need to verify that a method of a particular name exists, interfaces seem to be an 'inner-platform'.Safelight
@user151841: First off, it's ircmaxell (It's a pet-peeve seeing maxwell). Secondly, in a dynamic typed language it doesn't matter (for the most part) what was returned. If it returned a non-string, it would be cast to a string when you first used it like a string. The only time it matters, is when you're expecting an object of a certain type. And for that, you can do a simple type check if (!$return instanceof MyExpectedClassInterface) { throw new Exception... But for the majority of the use cases, enforcing the return type would almost go against the loose typing nature of PHP...Caramelize
@ircmaxell: But that is exactly the question (which in my opinion hasn't been answered yet, maybe touched in comments but not as an answer): The "full" description of interfaces (or protocol) in oop includes the return type. php implements an oop-ish concept of interface. Is the return type an integral part of the usefulness of interfaces or not? (And I'm not taking a side on this subject ;-)) Btw: php currently enforces default values on interface implementations but only that there is a default value if the interface declaration provides one, but not which one.Stocky
@ircmaxwell apologies about the name; can't fix it now :(Safelight
@ircmaxwell You seem to be arguing my point in your '2nd'... interfaces don't get you much in dynamically typed languages? If all it gets you is guaranteeing that a method of a certain name exists, then the whole idea of interfaces seem a very roundabout way to do it.Safelight
@user151841: I'm not going to argue about this. They "don't get you much", because (from a return type perspective) they don't need to. The interface is there to lend both a semantic implication (which depends on people using them properly) and an enforcement upon the actual class structure (so you always know an object of the iterator interface will always have a next() method that takes 0 parameters... There's nothing you can do (or IMHO should do) about people abusing the interface to do other (unsupported) things. If they do and it breaks, it's their fault, not the language...Caramelize
@user151841: It's not just the name. It's also the number of arguments. And with php 5.3 it also enforces type-hinting. If the interface contains type hinting, e.g. interface Foo { public function bar(Base $x, array $y=array()); }, then the implementing class must use the exact same type-hinting (no covariance allowed).Stocky
@ircmaxell: With type-hinting you can enforce certain behaviour of the input parameters, but you can't enforce the type of the return value. At least it's a bit asymmetric if we keep to the argument of "loose typing is the nature of php". And regarding iterator: One big thing in java (and .net) was the introduction of generics, so the declaration of next() wasn't limited to the broadest type object but could be limited to e.g. Integer and narrower. The question still remains: If php puts the interface in the oop section is not enforcing the return type a game breaker?Stocky
@Stocky If you write up an answer, I'll upvote and accept it :)Safelight
@user151841: Sorry, I can't really make up my mind on this subject in the context of php (and I gave up developing in php for a living quite some time ago so I don't have to -_-). I just use it for what it is.Stocky
I still contend that just because interfaces don't include the return type, they are still quite useful. In a strongly typed language, they would be a lot less useful since you'd need to figure out the type of the return before moving forward. But since PHP is loose typed, I think the loss by not having it is relatively small. I don't consider the lack of return type a game breaker (or even a set back). I think interfaces are wildly useful even as they exist today. But it still boils down to the proper implementation if an interface still falls to the developer (no matter the language)...Caramelize
N
1

Design by contract is made more difficult without return types, but don't forget to favour 'tell' over 'ask'.

I believe an interface to be something like a responsibility. You are coding and need a collaborator. You ask it to do something because the code you are working on can't do everything. So you're asking another object to do something. An interface guarantees that the collaborator will do the job, but hides the 'how' it's done part.

Now you could argue that there's no need for the formal contract here, since the system will throw an error anyway if the collaborator can't do what you're asking it to do. But I think that misses the point in using interfaces as a responsibility.

Nippy answered 25/8, 2010 at 18:19 Comment(0)
C
0

Getting a fatal error is not always "easy". Sometimes you have to go on a specific module/action to see that something is actually missing in your class. The interface enables you to make sure every method is implemented and to document these method (what the parameters are exactly going to be, what the return values should look like). This is useful if the parameters/values are arrays with a particular structure and you don't want to use classes instead (for the sake of simplicty).

Clostridium answered 25/8, 2010 at 16:36 Comment(6)
"what the return values should look like" - but that is not enforced by php (and user151841 picked up that aspect, too, in the question). So, "to document" is to be taken literally; external tools and/or ide may pick up that extra information/annotation but php itself doesn't care.Stocky
@Clostridium I'm not familiar with many other language. Can you give an example in PHP where you call a non-existent method on a property, and there is an obscuring of what exactly went wrong?Safelight
@Safelight : No, I can't, why would try to do such a thing? What I was saying is that it is harder to make sure that every method you are supposed to implement is implemented if there is no interface. You have to search all the code of the application for calls to the getters of the property, and then see what methods are called on it. Unit-testing all your app can help you find fatal errors, but an interface is far more convenient.Clostridium
@Clostridium I mean, I've never had a problem getting a fatal error. Calling a method that doesn't exist invariably produces one, and it explicitly tells you where exactly it is (file and line). So in short it's "easy", at least PHP. It makes an interface redundant, at least for the purposes of ensuring that a method name exists.Safelight
@user151841: Yes it is redundant, but it is more convenient. All you have to do is read the spec and implement, instead of testing all your app, and noticing on test #481, that someMethod() is supposed to exist... This is even more true if you did not write the interface and the class that calls someMethod() on an object of the class you are supposed to write.Clostridium
@Clostridium I see -- one-stop shopping for what you need to do to write a class. Your requirements all in one place, like a spec. Makes sense.Safelight
L
0

I want to note, that PHP 5.4 will support type hinting. Right now I think there is only type hinting for function arguments, but I suppose there will be for return values, too. (At least there already is an RFC, though a very old and outdated one.)

Lowrance answered 25/8, 2010 at 16:45 Comment(5)
It's there, but it's still a very contested feature... I'm not in support of the current implementation... I think it's WAY too strict to be usable.Caramelize
I meant for argument type hinting. I haven't heard anything about return type hinting... Sorry for the confusion...Caramelize
Why do you think the current implementation is too strict?Lowrance
Because if you have function foo(float $bar), and call with something like: for ($i = 1; $i < 10; $i++) foo($i / 2); you'll get a fatal error (since 2 / 2 == 1)... So you'd be forced to check your types before calling. So it breaks the accept liberally produce strictly principal... If it supported method overloading (where you could define foo(int $bar) and foo(float $bar)) then that could be worked around, but without it, it's going to make pre-call type checking a lot more important. And considering the loose typed nature, it's going to make for some interesting bugs...Caramelize
Not to mention that it kills all the benefits of type-coersion that's available in PHP. If you pass an object that has a __toString method to a function that has a string type hint, you'll get a fatal error (rather than an implicit conversion to a string first)... So it's going to require explicit casting in the calling statement to prevent fatal errors (foo((string) $bar)...Caramelize

© 2022 - 2024 — McMap. All rights reserved.