How is the contrast? The HDR content? Any downsides?
I will upgrade to M4 Pro and really hate the glare when I travel (and I do that a lot) but at the same time I don't want to lose any quality that the MBP delivers which is quite excellent imho
const user = {
firstName: "Seán",
lastName: "Barry",
email: "my.address@email.com",
number: "00447123456789",
};
if (!user) {
throw new Error("User must be defined.");
}
if (!user.firstName) {
throw new Error("User's first name must be defined");
}
if (typeof user.firstName !== "string") {
throw new Error("User's first name must be a string");
}
return user;
The early return pattern was the most effective single piece of advice I received from a senior dev on how to make my code more readable. You end up with clearer code paths than any other pattern I have seen so far and way less indentation making things look (and probably perceived) as less complex.
Pair it with naming your complex and chained expressions and suddenly you have some seriously readable code.
So far, I have never seen a valid scenario where a switch statement is actually any better than if.
I think the early return pattern makes the most sense when it's less "logic" and more "validation." Eg in the example, the code isn't really _doing_ anything if there's no user or no first name, it's running a bunch of checks _before_ trying to do anything. Those validation checks are implemented with if/early return, but the actual pattern is more "validate first and only proceed if everything checks out."
In typed languages a lot of those checks get implemented in your actual types, but you still might have various business logic/data integrity checks you might implement in early return.
Seen in this light, this pattern's really not so much in tension with the idea of having a single return variable. It's just a way to implement the idea that invalid states should not be possible, which you accomplish in your type system when and if possible, and fall back to runtime checks for the gaps where it's not.
Early return can get into trouble if you're talking about a function that has a fair bit of state to unwind in the event of an error. Open filehandles, allocated memory, general cleanup stuff.
That said, I much prefer early return whenever it makes sense. In functions that do have a lot to unwind and many possible points of failure I'll pull out the old villain 'goto' and have the unwind code at the bottom of the function.
Strictly sticking to only one approach is usually a mistake. One that is repeated a lot in computer science. There are schools of thought that if everything is the same it will be easier to understand, but what happens is problems that don't exactly fit the mold end up being solved in awkward and inefficient ways. Or development gets slowed because you have to refactor your problem around the tools instead of the other way around.
> Early return can get into trouble if you're talking about a function that has a fair bit of state to unwind in the event of an error. Open filehandles, allocated memory, general cleanup stuff.
This is where Lisp's unwind-protect, finally blocks in some languages, defer in Go, and C++'s RAII pattern can come in handy. Especially if you have a healthy respect for goto and want to minimize its presence in your code for various reasons.
`finally` introduces additional blocks, so if you have 5 different resources that you acquire as your function goes along, you end up with 5 levels of curly braces. Not very elegant.
`defer`, on the other hand, is probably the only thing I wanted to take from Go to other languages I worked with. Beautifully explicit and wonderfully useful.
It would be cool if someone made a way to scope variables at the function level in JavaScript instead of at the block level. I might write a transpiler for it…
It would be nice if there were an equivalent in the native API. You can use .finally() with chained promises, but as far as I know there's nothing comparable with async/await yet, and that's a much more comfortable syntax with which to work with promises overall.
Unpopular opinion: I think early-returns make code less readable if you don't put the rest of the function in an else clause. You lose visual parallelism, and suddenly instead of following a tree down to a series of leaves where every leaf terminates, you have to have the full context to know whether or not a line of code may not execute in some cases. For example:
function foo(x) {
if (x == null) {
return null;
}
x += 2;
return x;
}
I can't just look at "x += 2;" and know whether or not it's conditionalized. I have to have the full context including the early-return, and then reason about the control flow from there. Whereas:
function foo(x) {
if (x == null) {
return null;
} else {
x += 2;
return x;
}
}
Here I can tell just from the else-block that this is one possibility which will execute if the other one does not, and vice-versa. Their indentation is the same, cementing their relationship. If I want to know whether this block will execute I need only look at the if()'s, not their contents.
I think your version isn't really as different as it seems to some. To me, the essential bit of early return is that you handle cases that eliminate the work first. That is, it's less about singular if statements separating the rest of the body of the function than it is clearly short circuiting the code as early as is clearly possible.
That is, I don't think it matters too much whether you do:
function div(x,y) {
if (y == null) {
return null;
}
if (y == 0) {
return null;
}
return x/y;
}
or
function div(x,y) {
if (y == null) {
return null;
} else if (y == 0) {
return null;
} else {
return x/y;
}
}
as they both accomplish the same major benefit of the pattern.
The real thing it's helping to avoid is accidentally creating something like this:
function div(x,y) {
if (y != null) {
if (y != 0) {
return x/y;
} else {
return null;
}
} else {
return null;
}
}
which can quickly get very hard to reason about without in more complex cases.
You're right that both technically qualify as early-return, which is why I qualified my original statement with "if you don't put the rest of the function in an else clause".
In practice, in C-like languages, I tend to see the "else-less" version which is why I brought it up
If you haven't seen it, Kevlin Henney's talk about "The Forgotten Art of Structured Programming"[1] is interesting (if somewhat long in the examples later), and somewhat related. It's not specifically about return early (and a case could be made that it should or should not apply specifically to early return), but it is about if, else, return, and how they affect cognitive load when reading code.
On the contrary, if early returns allow you to outdent a larger portion of code then it's quite a readability win. As long as all the early return cases are bite-sized and the last case long-ish, it's a readbility win.
I really miss postfix conditionals from perl/ruby/coffeescript in all of the other languages. (Along with until/unless, which are just while! and if!.)
I asked on the go-nuts mailing list about perhaps including them in go2, but it seems many of the people who replied hate them.
I have the same opinion. I like the early-return pattern when it's doing input validation or raising errors but for most other things I prefer how the if-else highlights that there are two possible paths that the code can take. Just because the "then" branch has a return statement doesn't mean that we should get rid of the "else".
I think the bigger problem you may be experiencing, if I had to guess, code structure.
If people tend to write:
function foo(x) {
if (x == null) {
return null;
}
// do some stuff to the code
for(a reason) {
// do some more stuff
if(some detailed reason) {
return null;
}
// more things
return 7;
}
Then the shape of the code and the "pattern" of early returns gets broken.
If you read code where all of the short-circuit, early-return logic is at the start of the function, and then all of the work is done, do you still have this opinion?
E.g.
function foo(x) {
if(x == 1) { return null; }
if(x == 2) { return null; }
if(x > 7) { return null; }
// do things with x
return 7;
}
?
The problem is definitely much worse when returns are scattered throughout the function instead of grouped at the top, but I still prefer them to be "elsed" together (or in a switch/cond/match statement or whatever). Worth noting that in Lisp - one of the classical languages where early-returning is popular - there isn't a problem because it is done as I describe:
If you want elses everywhere, how do you protect yourself from nesting hell? I find nesting hell to be far, far, faaaar worse for readability than any of the alternatives, and will move to the early return model to escape all that nesting.
I dunno, I just rarely ever find myself nesting more than two or three levels of conditionals even in extreme cases. If my logic really is that complicated, it's probably a sign it needs to be broken up anyway. And if I did need that much branching, I would want to be more explicit about it, not less.
Also - at the very least - you can mimick the "flat" early-return style and just stick some else's in there and call it a day. That's my main point; less so the actual deeper nesting
Well, the way it was written, I was assuming that conditions to be satisfied had separate named predicates (although combinators could alleviate even some of these things).
I recall this pattern being taught in my first year or two of my computer science degree. Emphasizing only one return statement per function, utilizing a shared return variable.
I much preferred (and still greatly prefer in industry) the pattern of exiting the function as soon as possible.
I find the safe way to program that is always to set the initial value to some error. You only set it to success at the point you succeed. Then you never have to worry about some odd goto or other break in the control glow being introduced by you or someone else that wasn't paying attention. It's also better self documentation, because then it's obvious at what point you're actually done, in the case your final work isn't aptly named "last_bit_of_work(work)", because you'll see the return variable set to E_SUCCESS immediately afterwards.
agreed, but some people dislike that because you have to have an E_UKNOWN or E_GENERAL or something like that in addition to more specific errors and others dislike it because now there's not something to conveniently store results from called functions in so that they can be checked for errors.
I see that as a sign that the person learned how to program in the 80s/90s when things were still in a phase of overreaction to the popularity of BASIC and GOTO. GOTO is bad, therefore return is good, and single return is best. Not actually good logic, but that was the thinking at the time.
Early return is my silent gauge to tell if a piece of code has been written by a junior or a senior software engineer.
I still see far to many snippets with multiple levels of indentation, where each if branch is for the happy path, and if they were converted to early returns you could flatten the whole thing to 1 indentation level, at the expense of requiring negated boolean expressions which aren't as readable.
No need to ‘return’ when you throw an error, but your approach is valid IMO: if structure / readability is that important, refactor the switch to it’s own method with only if checks in it. Hard to make that simpler and more readable.
If you don't have a 'return' there's nothing to say that some time later some junior developer would not modify throw to be something else or forget that throw does not return.
I've grown to dislike the early return pattern. It's pitched as a way to reduce visual complexity by reducing levels of indentation, but I don't actually find that to be a benefit in most cases. Reducing indentation is just a trick to shove more cyclomatic complexity into a function without it triggering your sensibilities to implement proper abstractions.
_ = !isDefined(user) && throw new Error("User must be defined.");
_ = !isString(user.firstName) && throw new Error("User's first name must be a string");
But I while it is concise, I can also understand why people prefer regular if statements.
Doesn't seem to be valid JS, can't remember where I got it from
In perl you would want to use `or` instead of `||` to take advantage of the low precedence, so you can type things like `dostuff $foo or die` which is logically 'do stuff, and if it fails, die' as opposed to 'die if $foo is false', which you'd get with ||
I agree; `if (` is much more well-known and "grokkable" to engineers at practically any level than `case` - and exactly the same number of characters. There's no need to bring a sledgehammer when the nail is perfectly handled by a normal hammer.
I think the issue here though, is that for certain cases such as form field validation, you want all issues to be returned at once. Using the switch method or similar message packages allow you to inform your users that have N issues with a page in 1 request as opposed to N.
That’s not how throw works. And that’s exactly why the switch(true) pattern should not be used: novice users not fully knowledgeable about every specification of a language should not fail to understand such a basic piece of code.
There’s not even a line difference to using if statements correctly (as others in the comments have demonstrated)
The one thing an if statement does is checking if something is ‚true‘. I don’t understand why anyone would use a ‚switch‘ here apart from showing how clever they are.
Either you will break, thus exiting the switch-case block or you will fall-through. The fall-through behavior won't do what you want:
> the script will run from the case where the criterion is met and will run the cases after that regardless if a criterion was met.
Using the switch method won't allow you to return several errors while the simple ifs method described earlier could accumulate the errors and return later. The switch method is elegant though.
...is this guy for real? One of the first things that designers do during the design process is to check how a certain problem was solved by others. The goal is to make it work well not to make it original.
Not necessarily. I view the advertising industry as a net loss to society, yet the amount of revenue is immense and the salaries of the people working there are equally large.
Yes, the idea of exposing potential consumers and informing them of what your product is in principle fine, but that idea was perverted long before any of us were born. Now it's about spending money on selling products that aren't selling themselves, because it's cheaper than making a better product. As always, exceptions exist.
OP wrote: "I would have been far more qualitatively useful to society at large."
There are far more people that need UI work (in the form of websites, apps, etc) these days than art. UI work scales very well, art not really - you can affect way more people and that is reflected in the salary.
"Qualitatively" UI work is far more useful to society.
Earning money is not easy. The fact that on average a larger group is willing to pay for UI work than for art indicates that UI affects their lives more than art and is more worth to them. Whatever one's reason is.
That doesn't really work. Is my life better or worse if I feel worse about myself because I become aware of the way that I'm part of a unethical social system? Given the choice, I wouldn't choose to be a happy person who lives in the Jim Crow south and supports segregation. Part of what many artists do is help people understand themselves differently. You can't assume people are going to be willing to pay for something that's good for them (by their own standards).
My skills are now very bounded to building interfaces for consumption, not critical thought. In fact, the choices I make for developing interfaces usually revolve around the user being some level of drunk.
My senior thesis was a receipt printer that wireshark'd instant messenger messages on our school's unsecured wifi and dumped those messages into a pile.
...so you are not critically thinking about your work in the context of how useful it is to the end user? That's a bad UI work, I'd say.
As for your senior thesis - Developer's job is to create software that makes lives easier. It was your decision to use your skills to harm people by exploiting their privacy.
Or it could be seen as something good - you discovered a way to exploit people and if you informed whoever was running this app you helped a good amount of people in your school.
I think you're misunderstanding both my role as a UI developer and as an artist...
It takes critical time and energy to reduce the complexity of a products' features to something a layperson can use, and a layperson is usually barely paying attention.
As to your second point, I wasn't a developer, I was an artist, attempting to ask real questions about privacy and spark real discussions and possibly getting myself in trouble to start a conversation.
How many people work full time ubpaid on the Linux kernel? For the 4.15 kernel, AMD, Intel, Google and Red Hat contributed between 35 and 50% of the changes, depending on whether you count number of commits or number of lines changed.
I think you may be picking up on a but of a cultural difference here. In America, people are identified, both by themselves and by others, in a large part by there job. It's a huge part of personal and cultural/societal identity.
oh man, that's exactly my experience - I get shit done but I'm perfectly aware that what I'm doing is not near my real capabilities. And tech life allows you to smoke every day without consequences - good money, no strict working hours, no one watching you work etc.
"complex and expensive cashierless stores that won’t deliver much of an improvement to our shopping experience but may cost underprivileged people their jobs"
Cashierless stores are simple and amazing. I won't even comment the part about "underprivileged people", this is straight up dumb.
This is a time when an entire driverless car industry is trying to convince the world that its products are safe before it can even come up with convincing stats -
Nearly 1.3 million people die in road crashes each year, on average 3,287 deaths a day. An additional 20-50 million are injured or disabled. More than half of all road traffic deaths occur among young adults ages 15-44.
THAT is not convincing enough? Autonomous cars are the future and will allow us to focus on other activities during the daily commute or long distance travels. Will decrease deaths, will optimize energy consumption by intelligently setting the right route and speed. Humans are inferior to computers on the road, that's a fact.
Your narrative is a thing which could happen, not the current truth on the ground. The truth is every time a Tesla rams into a stationary object at speed, or an Uber runs down someone crossing the road, the public’s faith in the tech erodes. Every time that happens we edge closer to overburdensome regulation in the “Thanks to 3 mile island & Chernobyl it’s basically impossible to build a new nuclear plant in the US” sense, and farther away from your utopian dream.
Accidents will happen, that is inevitable. Autonomous cars don't have to be perfect - they only have to be better than humans and that bar is not set very high.
There are very little examples of autonomous cars causing trouble on the road and plenty of them preventing accidents - an example would be videos on youtube showing Teslas predicting accidents in advance and taking action.
> they only have to be better than humans and that bar is not set very high
Not to rehash this discussion, but: the bar is actually set very high, and current self-driving tests are seemingly not meeting it. There's a lot of deaths because there's a whole lot of driving.
Vue is not a framework, at least not in it's simplest form - drop in UI library.
I agree that Vue does much more than Intercooler and in theory, it could be seen as an overkill. But in reality, a developer will probably use it in conjunction with jQuery and then he might be better off replacing these two with Vue.js
I mean, regardless of anecdotal specific usage, vue is a framework. And a nice one too! Just entirely too much for something that can be fulfilled by a simple pjax tool
I will upgrade to M4 Pro and really hate the glare when I travel (and I do that a lot) but at the same time I don't want to lose any quality that the MBP delivers which is quite excellent imho