-
Notifications
You must be signed in to change notification settings - Fork 9
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
Implement protocols on null #43
Comments
It should always be impossible to have a protocol on null (or undefined) because they can't have any properties. |
I explained that I have a library where I implemented protocols on null. It's just trickery, all in the implementation. Not impossible. And it's proven useful for a long while as Eric Normand explains. |
Right - I didn't say it was impossible in a library, i said I believed it should be impossible in the language. |
Heard. But I'm making the same cases Clojure makes for its usefulness. And this thread is about putting a voice to a position. With protocols you can iterate over a sequence, whatever its nature (e.g. concrete type). So when Null is considered a proper type from a protocol's perspective, iterating over it means zero iterations. It's a workable default that makes having to code around null less of a problem, and without having to Maybe monad everything in a language that doesn't regularly use Maybe monads. There are many other protocols where having a proper Null, and where the developer can decide how it should be handled by the protocol and just makes the fuss surrounding dealing with null go away. In my linked examples, I illustrate sensible defaults for null. These sensible defaults help simplify programming. It's not like you, the programmer are left to wonder if some nullish behavior is good or bad. You decided what it is since you're the one implementing it via the protocol. And if you don't like it having a behavior, you don't implement it and you deal with your null reference exception some other way. The behaviors in my code (linked) make those cases demonstrably clear. It's better to provide reasons beyond "I don't like it" when it comes to influencing the community to decide on some part of a proposal. I linked Eric Norman's talk and there are others which explain the value add. The good is, as I said, making it possible to allow protocols to be implemented on null, doesn't force the matter with anyone. That's the beauty of protocols. They leave devs to decide behaviors. |
I'm not sure why you'd need the protocol to be "implemented" on null? Whatever code interacts with the protocol could simply special-case null, no? |
It's the having to put a conditional statement around everything which is the very problem protocols intend to eradicate. The point is the conditional is moved from the code and every instance you deal with types to a central location. |
You'd need to handle |
In my library I deal with I've been nil punning with my library for almost a decade. The thing I've found about those who sometimes make counterarguments (I don't know you are doing this) is that they may not have experience with the thing they are arguing against. That is, it's hard to knock a thing you've never actually tried on and to think that because you learned one way (e.g. TypeScript, whatever) that the other way is not useful. Remember, my suggestion is opt in not absolute. Like the contested default ES6 exports. Use 'em or don't. |
Lots of code treats them as distinct values, including the very language itself - so while that's a fine position to hold as a dev, it's simply not one the language should ever be holding. Both values exist, and are distinct, and some features distinguish null and undefined while others lump them together as "nullish". I've certainly not used this technique before - but I'm not debating its usefulness, I'm taking that as a given, I'm trying to understand how it could coexist in a language where |
This is an opt in suggestion, so it would allow me to go my way and you to go yours. |
If it's opt-in, then I'm unclear as to why the implementations of the protocol, which you control, can't special-case null/undefined as you like? |
Why don't you demonstrate what you're thinking with code and then I'll explain, because I'm not sure what you're thinking. protocol ToString {
tag;
toString() {
return `[object ${this[ToString.tag]}]`;
}
} How would you implement that for null? In my library it would look roughly like: function toString(self){ //`self` is null (or undefined)
return "";
}
Protocol.implement(Nil, ToString, {toString}); And that would look identical to how it'd be implemented on a String or any other type: function toString(self){ //`self` is already a string
return self;
}
Protocol.implement(String, ToString, {toString}); Keeping both of these implementations the same is what makes implementing protocols a pleasure. The conditional is abstracted away. |
ah i get what you mean. you wouldn't, because null and undefined can't have methods, so indeed every caller always has to account for that, everywhere in the language. What you're asking for is a much much larger feature that would affect the entire language - I don't think protocols would be the thing to add it. |
Just look at my implementation, which I've realized and used for years as a blueprint. It's trivial. And I'm sure professional language implementers could do it even better than me. |
Creating a |
In my case I defined a Use the same internal trickery I used for greater good. Call it Just make it possible to call protocols against anything including these untyped concepts because, if you don't, you're stuck handling nulls everywhere as an exception. And, again, that forfeits the gain that protocols give you (making everything homogeneously respond to a certain set of messages). I'm suggesting that excluding null/undefined weaken the benefit of protocols substantially since null is perhaps the most prevalent (non)value. |
It's worth noting that the proposed implementation only considers protocols for objects, things which would have a protocol Ordered {
compare;
lessThan(other) {
return this[Ordered.compare](other) === Ordering.LT;
}
} Assuming you want nulls to be comparable (they should be because it will happen!) this won't work. You'd never get your When I implemented protocols I wrote my implementations to explicitly pass the subject. protocol Ordered {
compare;
lessThan(self, other) {
return self != other && self == null || self[Ordered.compare](other) === Ordering.LT;
}
} Doing it this way you provide a way to special-case and handle nulls even if you don't bother deferring to a Allowing for an explicit self makes it possible to include nulls as a comparable, which is useful if it's present in an array to be sorted. It allows the dev to specify how nulls sort. |
@mlanza What prevents us from supporting |
@michaelficarra - I've been looking at the proposal and I see plenty of examples for implementing protocols, but none for actually invoking them. Has the invocation syntax not been determined? Given const stooges = ["Moe", "Larry", "Curly"];
Functor.map(stooges, stooge => stooge.toUpperCase()); //1
Functor.map.call(stooges, stooge => stooge.toUpperCase()); //2
stooges[Functor.map](stooge => stooge.toUpperCase()); //3 The first looks best to my eyes, but I can't find it demonstrated anywhere. This has a bearing on a follow-up question I have. If determined, it might be good demonstrate it in the README with examples. |
Protocols are just a way to:
|
That's awkward. I've called out some problems with it. I'll revisit this topic, when the newly-linked one reaches a consensus. |
With extensions proposal (I plan to rename it to "dispatcher" proposal), it's possible to support The initial proposed syntax is |
@michaelficarra I think protocol should use method style. Even we use function style, developers still facing the chaining problem and would ask for pipeline operator. |
I've been using a library I wrote for nearly a decade now where I implemented protocols as one of it's central premises, because I find them so useful in how I think about writing programs.
Since null doesn't actually inherit from a class and is its own thing, it was not possible to implement protocols on null in the same way as on types, but I did it. I basically have an exception (a loophole in my protocol processing) that recognizes null as a special circumstance and then defers to a Nil type I defined. On that custom type I implement the protocols null uses.
I can tell you firsthand that nil-punning (treating null as a type) is incredibly useful if you don't want to have to continually code around null (or use the Maybe monad), especially in situations where it doesn't matter, and from my experience that's often the case.
The text was updated successfully, but these errors were encountered: