10 ms·
Why are there no return statements in Objective-S?
- user-the-name 5y ago"return" is good because it signals intent. It lets you communicate to both the compiler and at least as importantly, to the reader, that this is the value you intended this function to return. The compiler can then warn you if you return a value when you weren't meant to, or if you forgot to return one when you were. And the reader can tell at a glance that this value is important.
- mpweiher 5y agoYeah, that's one of the good reasons for having a return statement. I don't know if it outweighs the reasons not to have a return statement (yet). Another issue is that there are actually 2 functions of the return statement: (1) it sends a result and (2) it terminates the method/function/whatever. In call/return, those are the same, but more generally they are not, and Objective-S wants to make it easy to not default to call/return semantics. And that's difficult, because we are so incredibly used to call/return semantics that it's often hard to see that another way is even possible, let alone practical. So in the design, I need to very deliberately push against what seems comfortable and familiar. Which can lead to insights or nonsense. We'll see how it turns out.
- ghusbands 5y agoHaving implicit returns has been a source of bugs and vulnerabilities in code [1][2][3]. Essentially, it results in accidental return of temporary values, especially in cases in which people don't want to return anything. [1] https://github.com/CodeNarc/CodeNarc/issues/450 https://github.com/CodeNarc/CodeNarc/issues/450 [2] https://stackoverflow.com/questions/24070544/suppressing-implicit-returns-in-swift https://stackoverflow.com/questions/24070544/suppressing-imp... [3] https://nug.xojo.narkive.com/GvvcWglM/bug-command-keys-are-absorbed-by-menu-handlers-on-mac-but-not-on-windows https://nug.xojo.narkive.com/GvvcWglM/bug-command-keys-are-a...
- slver 5y agoIf you don't want to return anything you'd declare your function return type as void, so that's probably more in dynamically typed systems.
- magicalhippo 5y agoWe've had cases at work where the issue is that a void function (procedure) is converted to a "proper" function, and some return paths are missed. For our compiler, for certain types it fails to warn that the return variable is unassigned, hence bugs occur. This is a statically typed language, it's just an unfortunate interaction between compiler magic and the code that checks for unassigned return variables.
- slver 5y agoWith a bit of practice, the intent of "the last expression is the one you return" is clear enough. That's not a problem I think. The problem is how to encode early returns in that context.
- user-the-name 5y agoWith a little bit of practice, you can get used to anything that reduces comprehensibility. That doesn't mean doing it is a good idea. Every time you do, you sacrifice a bit more.
- slver 5y agoCome on, that's not what I meant. "Last line of a function" is honestly a very blatant and obvious way of encoding a returning point (and hence returning expression in an expr-oriented language). You literally can't miss which line is the last line, UNLESS you're simply habituated into seeing the keyword "return". You said it's about communicating intent, not about matching current habits. Those are completely different things. For example, someone who knows Russian and is learning English, so they make mistakes in English. That doesn't mean English is a poor language for communication, does it? Case in point, do you actually type "return" in say Java, for a void method, when that return is your very last line of the method? Yes, no? If no, then you didn't need to communicate "it's returning here" with greater intent. If yes, then I'll accept your point about you finding no return ambiguous. But still, most people don't.
- user-the-name 5y agoBut it's not the last line of a function, though, is it? Put an if statement in there, and it can be literally any line of the function. Sure, you can still work out which one, but it gets more difficult. And, even if it were the last line of the function, you are still not communicating clearly whether the function is meant to return a value at all or not. This both hurst readability, and makes it easier to accidentally introduce bugs.
- 5y ago
- pwdisswordfish8 5y ago> The answer is that I would like to do without return statements if and as much as I can. We will see how much that is. In general, I am in favor of expression-orientation in programming languages. Rust is as expression-oriented as they get, and it does feature return statements (well, expressions: they have the empty type, implicitly convertible to any other type). I don’t see how those two are supposed to be exclusive. In fact, they very much go hand in hand: ‘expression-oriented’ is just another name for functional programming, and a return statement is just a limited (non-reified) form of continuations, a well-known concept under this paradigm. I don’t know what’s to write about here, really. Also, it’s pretty ironic to see the article support its claims by a quote from Guy Steele disparaging functional programming, immediately followed by an example like #Blinker{ #seconds: 1, #active: true} → ref:gpio:17. which looks like mapping over a generator in all but name.
- mucholove 5y agoMaybe it has to do with coherence of objects as collections of functions and the fact that they contain state. I love objects and talking about them as living creatures. :) They’re sort of like functions that include a long set of parameters. The one thing I wouldn’t know how to do / name in functional pure functional programming is an incremental parser. My sense is that would probably have to pass an “object” like parameter like in C that gets updated by the function. What am I missing?
- Dzugaru 5y agoYou pass a state and return a new, modified state. You can, however, "pass" many other things in functional programming - see monads (also called computation expressions). I recommend fsharpforfunandprofit website for gentle introduction into FP (and a language called F# which is basically OCaml) and what it can do (especially in parsers area)
- ProfHewitt 5y agoThe monad pattern can much less efficient than concurrency by factors of hundreds.
- codeflo 5y agoPeople say that OO is “meant” to be about message passing all the time, quoting Alan Kay and others. I never found this helpful. No mainstream OO language works this way, even Smalltalk doesn’t. You can’t design or understand real-world systems(1) with this message-passing metaphor, it will only mislead you. Objects don’t “do” anything, they are simple passive data structures that are acted on by procedures. A certain set of procedures with privileged call syntax and visibility into the data structure are called its “methods”, that’s all the magic. The sooner you accept this, the better your designs are going to be. (1) Edit: I meant here that you can't design real-world systems that way in OOP languages. I left that out because I considered it obvious from context, but it seems like it wasn't. I didn't mean to disparage any actual message-passing systems. My claim here is that OOP, as commonly understood and implemented by Alan Kay himself in the form of Smalltalk, is not about message-passing. Erlang is, but that's a different topic.
- DemocracyFTW 5y agoThis! I never understood the why for this 'send-a-message' way of talking when what I do is really call a function that may or may not affect the state (of the object it is being called on or any other object).
- masklinn 5y ago> I never understood the why for this 'send-a-message' way of talking when what I do is really call a function Because you don’t, dynamic dispatch means you don’t know and are not supposed to care how the object handles or responds to the message. That is maybe more flagrant in Self.
- User23 5y ago> “By allowing general architectures, Objective-S is the first general purpose programming language. What we currently call general purpose languages are actually domain specific languages for the domain of algorithms.“ What is this supposed to mean? Perhaps I’m being dense, but it looks like nonsense to me.
- mpweiher 5y agoI would expect it to look like nonsense to many if not most practitioners. It would have seemed like nonsense to me a year or two ago. The issue is incommensurability (https://en.wikipedia.org/wiki/Paradigm_shift#Incommensurability https://en.wikipedia.org/wiki/Paradigm_shift#Incommensurabil... ), though I find the idea that communication or translation is impossible a bit too strong. But it definitely is very difficult. As a start, think of what ALGOL stands for: ALGOrithimic Language ( https://en.wikipedia.org/wiki/ALGOL https://en.wikipedia.org/wiki/ALGOL ). Now think which current mainstream language is not derived from ALGOL. There are some variations, but they are fairly minor. OO languages attach the procedures to the data structures, and call the result methods and object respectively. FP languages insist procedures must not have side-effects and call them functions. And so on. (And once I remembered what ALGOL stood for, I thought that what I had thought of as a deep insight was so trivial that obviously everyone already knew it. I guess not :) ). Anyway, my first semi-coherent written account of this is here: https://2020.programming-conference.org/details/salon-2020-papers/5/Can-Programmers-Escape-the-Gentle-Tyranny-of-call-return- https://2020.programming-conference.org/details/salon-2020-p... In short: the first thing we used our computers for was computing answers. For this functions/procedures are well suited, and so we also used procedures (sub-routines) as our structuring mechanism. The problems we are solving with our computers have changed dramatically, but our structuring mechanism has remained essentially the same. Another short: software architecture defines many different kinds of connectors and components. The procedure/function call is just one of them, but that's the one that is directly supported by the majority of our programming languages. So if we need a different architectural style, we have to cobble it together out of procedure calls.
- ghusbands 5y ago
- mucholove 5y agoThank you for such a thoughtful answer! I did ask the question on Twitter. :) Not entireley convinced but I’m certainly looking forward to using it. One more thing—how would you do error handling? Thinking out loud here: it would be nice if NSObject had a method `isError` that went something like `self isKindOfClass:[NSError class]` so that you could return error in a more clean way. Wonder, what would mpw do? Another question—how to MPW multiple return items? (My guess is that the return items would be mutable? Like a mutable string. Could work with numbers if you had such a thing as NSMutableNumber.)
- 0x10c0fe11ce 5y agoWrite that method in a category of NSObject and you’ll have it now. Objetive-C is a very extensible language with lots of syntactic sugar to help us out. Also, meta programming is lots of fun, but impossible without diving into the runtime guts which is part of the fun.
- mucholove 5y agoThe only thing that stops me from doing it that there is a well established pattern of passing `&error` which tells me that the function can error and that I could handle it. I’m sort of looking for what 2nd order and systemics effects `mpw` might expect. To me, Swift is a bit more annoying with `if let`. Seems like it might provide a benefit, but it’s not so compelling to me. The compile times are so much slower so as to turn me off completely.
- superjan 5y agoWhat I like about return statements is that encourages me to think about the special cases one by one and be done with them. This also reduces nesting. This could be solved by pattern matching as well, but that might not be a good fit for any language.
- pklausler 5y agoThe most correct code that I write is in pure functional languages (or C++ in the functional style that has been practical since '17), and I could argue that they comprise only declarations and what would be considered to be "return" statements. I like this paradigm because the structure of pattern matching and recursion lends itself well to little proofs of correctness.
- ProfHewitt 5y agoGood point. The proofs of correctness for expression programming languages are a special case of the proofs for Actor programming languages. See the following: https://papers.ssrn.com/abstract=3603021 https://papers.ssrn.com/abstract=3603021
- ProfHewitt 5y agoTechnically speaking, an Actor does not do a "return" for a request it has received. Instead, the Actor sends a 1-way message to the customer Actor that it received with the request. Actors operate concurrently, which is different from the object-oriented programming beginning with Simula.
- mpweiher 5y agoExactly. From TFA: "With those more general semantics, "^" might also be used to send back results to the sender of an asynchronous message, which is obviously quite different from a "return"."
- ProfHewitt 5y agoTechnically, speaking the response does not go to the sender of the request. Instead, the response goes to the customer that was received along with the request. For example, tail recursion makes of the ability to specific a customer along with a request. An Actor never knows where the request came from. Of course, the request my be signed to designate accountability for the request.
- mpweiher 5y agoa) Technically TFA never mentions the word "actor" so your mincing such fine meat regarding the exact wording of definitions in actors is utterly irrelevant. b) sender / "customer" / whatever. Whoever gets marked as the "receiver of results". From TFA: "I've already taken that and generalised it to mean "send result", using it in filter definitions, where "^" means "send a result to the next filter in the pipeline"