You're better off using Exceptions - <AUTHOR> https://eiriktsarpalis.wordpress.com/2017/02/19/youre-better-off-using-exceptions/ <comment><USER3> My problem with exceptions isn't so much exceptions themselves but the way they're used.

The way I see it, exceptions should only be used for things that are irreconcilable, which most of the time is interpreter errors(e.g. undefined is not a function). In other words, I don't think it's that common that custom exceptions are needed outside of assertions to prevent the developer from doing something stupid. If you aren't using types, raising an exception can be helpful to provide feedback and useful information when data isn't formatted correctly.

Exceptions suck when they're used for problems that aren't actual problems. For example, if a query is made to an API for a record and that record isn't found, the SDK wrapping that API would raise a "Record not found" exception. What the hell? A record not being found is a _normal_ thing! I've seen this kind of thing all over the place, and I recently had to write some application code to work around one of these useless exceptions. They literally tell you nothing and there's no way to solve them without catching/rescuing them. A null value, a plain "error" object, or an error argument in a callback would have been sufficient. If I need an exception to be raised for this kind of thing, I'll do it myself.

<comment><USER4> > A record not being found is a normal thing!

It's _not_ a normal thing for code that needs that record that wasn't found.

> They literally tell you nothing and there's no way to solve them without > catching/rescuing them. A null value, a plain "error" object, or an error > argument in a callback would have been sufficient. If I need an exception to > be raised for this kind of thing, I'll do it myself.

They tell you lots: you asked for something your code path wanted and your request couldn't be satisfied. Also, you've been helpfully kicked onto the alternative execution path to handle that situation.

Exceptions are a hell of a lot better than littering your code with null checks or error code checks, especially when you forget one and get a null pointer error or your code wanders away from the root cause and fails later.

<comment><USER3> > It's not a normal thing for code that needs that record that wasn't found.

No offense, but I don't know where that idea comes from. Systems are checking for records _all the time_ in ways where the absence of data doesn't necessitate throwing an exception.

For instance, a page, user, or piece of media on a website may have existed at one point but was since deleted, but still has a permalink floating around the net. Is it useful, in the case that someone clicks on such a link, to throw an exception when I can instead choose to render different page content when a record wasn't found? I'll never need a stack trace for that.

> They tell you lots: you asked for something your code path wanted and your > request couldn't be satisfied. Also, you've been helpfully kicked onto the > alternative execution path to handle that situation.

Why would I want a code path for expected behavior? I agree for cases like a failed connection, where the system is actually broken, but there isn't anything fundamentally broken about data absence.

> Also, you've been helpfully kicked onto the alternative execution path to > handle that situation.

That's not only presumptuous, but if I wanted that to happen, I can do so myself.

> Exceptions are a hell of a lot better than littering your code with null > checks or error code checks, especially when you forget one and get a null > pointer error.

Hmmm...

      const record = store.findRecord(params.id);

      if (record) {
        render('show-record');
      } else {
        render('record-not-found');
      }

or...

      try {
        const record = store.findRecord(params.id);
        render('show-record');
      } catch(err) {
        if (err.name === 'RECORD_NOT_FOUND') {
          render('record-not-found');
        } else {
          throw err;
        }
      }

I'll let people decide which one is better. I personally prefer the first one.

<comment><USER5> The code example is not convincing at all. Obviously a single if is much cleaner than a single try/catch block but that is not the comparison. The if needs to be replicated N times for every N things that could fail and that are calling each other in a potentially deep call hierarchy. The try/catch block only needs to occur once at a level that is above all of the N things that might fail.

<comment><USER6> In my experience, on the web there are two different kinds of things we might be fetching.

Some things are essential to the page we are rendering, and if they are missing we should 404.

Some things are ancillary, and if they are missing we should render a stub in their place. E.g., saying that a comment is from "deleted user".

Exceptions are a good fit for the former, where we want to unify every failure. They are a poor choice for the other case, where we want to treat each failure special.

Which case a given fetch represents is a choice that should be driven by the fetcher.

<comment><USER7> Why are they a poor choice for the latter?

They have a type, make it say MissingUserException and the special place can handle it in a special way. Ensure it is a subclass of some general exception type you also handle elsewhere and you're good.

Often people throw generic exceptions instead of using the type system.

<comment><USER6> In the latter case you will often want to pass "data or the fact the data was missing" along to other functions. With a result value (of whatever form) that's trivial. With exceptions, it's certainly plenty doable but it's messy.

</comment></comment></comment></comment></comment></comment></comment><comment><USER8> When I moved to Rust the constant error wrapping or converting annoyed me. But after using it for a couple of years it turned out to be a huge blessing. Quite often I need to know exactly which error messages will be thrown so that I can do things like internationalization. While exceptions are quite convenient for prototyping for production I'm now firmly in the typed errors camp.

<comment><USER9> I don't know Rust at all but what you're talking about sounds equivalent to (much maligned) Java's checked exceptions system?

I never understood the hatred checked exceptions received especially from the younger crowd. I still write Java at work and I still use checked exceptions whenever they indicate an error condition that must not be ignored by the client code. Many new to the project developers hate me for it initially because they can't just "roll out a feature" without being forced to take care of the corner cases but over time they love the discipline that's imposed on them by checked exceptions.

<comment><USER10> I haven't written very much Java, but here are some differences between Java checked exceptions and Rust errors as I understand them:

In Java, a function may throw a long list of checked exceptions, and these lists tend to grow to inconvenient sizes in larger programs. For example, if foo() calls bar() and baz(), which each throw 3 different exception types, then now foo() might throw 6 different exception types. In contrast in Rust, each function can only return 1 error type. If a function needs to represent several different types of internal errors, then the crate that it's in needs to define an error enum type with a variant for each of those. (Either that, or the function can use a generic wrapper error that can contain anything. This is less common in library code but pretty common in application code.) This shifts a lot of work from library callers to library authors, which is a good thing.

Someone with more Java experience will need to correct me here: I think it's fairly common to bulldoze all that complexity by declaring a function that just "throws Exception". That saves you from writing out N different types (and more importantly, from changing every transitive caller when a low level library introduces a new exception type). But it kind of defeats the purpose of checked exceptions, by throwing away all the info they provide. It's a shame that you have this "all or nothing" choice when it comes to exceptions and how much complexity you want to deal with. In contrast in Rust, wrapper errors can define automatic "From" conversions from the lower level error types they wrap, and the standard `?` operator automatically applies those conversions. That means that in many cases, a low level library adding a new error variant might not require any changes in its callers at all. The new information is there for callers who want to look for it, but existing abstractions around the error type generally just keep working.

<comment><USER11> I don't think this is a real difference. You can make the exact same API design mistakes regardless of which error delivery mechanism you use.

The important thing is for the API designer to think about the abstractions, i.e which types of errors should be part of the API and which errors are just implementation details that may change.

If the API designer is too lazy to put enough thought into that then the result will always be what you are ascribing to Java.

<comment><USER12> There is always an onus on an API designer creating an API to express it well. However I think the difference between good vs bad language (and a good vs bad API come to think of it) is that it makes doing the _right_ thing easy (lazy), and the _wrong_ thing hard.

I think about this when I think about GraphQL. I like GraphQL, I really do, but GraphQL's N+1 problem is why I don't recommend it. The easy thing is to hammer the heck out of your database, the hard things is to parse the GraphQL request and correctly transform it into a SQL statement. I just don't trust everyone on the dev team to not be lazy.

<comment><USER11> I agree with the principle, but in this case it seems very easy to do the _right_ thing in either language once you have done the hard work of designing a good API. The same goes for doing the _wrong_ thing.

</comment></comment></comment></comment></comment></comment><comment><USER13> > Such criticisms typically revolve around scoping considerations, exceptions- > as-control-flow abuse or even the assertion that exceptions are really just > a type safe version of goto.

Outside of the FP community where people care less about purity - <USER2> criticism is more that exceptions are hidden, they're all-or-nothing (either any function can throw, or no functions can, and not all code paths have runtime errors that you care about), and of course the overhead.

I also really disagree with the idea that result types have more boilerplate than exceptions. That just depends on the paradigms of the language you use, anyone can add sugar to make either easier/harder to read.

<comment><USER14> > That just depends on the paradigms of the language you use, anyone can add > sugar to make either easier/harder to read.

The questionmark operator, in particular, is what sold me on the possibility that this type of programming can be concise and ergonomic.

[https://doc.rust-lang.org/edition-guide/rust-2018/error- hand...](https://doc.rust-lang.org/edition-guide/rust-2018/error-handling-and- panics/the-question-mark-operator-for-easier-error-handling.html)

<comment><USER15> I've not used Rust before, but this looks a lot like monads! Can I map/flatmap over these or do I have to unpack them later?

If you _can_ operate on those like collections, Rust is a much more fun language than I initially gave it credit for!

<comment><USER14> Yes, you can map over them, and it's great! I think they satisfy all of the monad rules, but I'm forgetting what they all are at the moment.

</comment></comment></comment></comment><comment><USER16> > _It's by such misadventure that the working F# programmer soon realizes that > any function could still potentially throw._

That's your problem right there. "Invisible control flow", as Joe Duffy puts it.

[http://joeduffyblog.com/2016/02/07/the-error- model/#unchecke...](http://joeduffyblog.com/2016/02/07/the-error- model/#unchecked-exceptions)

What's needed are two distinct error mechanisms: panic/abandonment for unrecoverable errors (which can happen at any time), and then for recoverable errors, either checked exceptions in some flavor (including Swift and Midori's untyped `throws`) or Result types.

Once you eliminate invisible control flow, you're no longer "better off using Exceptions".

<comment><USER17> But then the failed code which decides if the error is recoverable, not the part of the code doing the recovering.

<comment><USER16> Yes!

We shouldn't expect downstream to wrap every array access which could be out of bounds in a "try" block. We shouldn't expect downstream to wrap every division operation in order to catch potential divide by zero errors. Those should be fatal errors, catchable only at a very coarse-grained level, because once they occur the program state is potentially compromised in a way which the programmer did not plan for.

The library author gets to decide whether a potential failure mode should expose a recovery API.

</comment></comment></comment><comment><USER18> Exception != Error

Old Ada programmer here. Example of reading bytes from a file... just keep reading bytes and don't include logic for checking for EOF. Let the exception handler catch it where the file will be closed. Clean separation of code.

In Ada, every bock can have exception handlers at the bottom. No need for "try" syntax. Very clean.

<comment><USER19> That is like C++ destructors, which are called deterministically when they go out of scope (again with no "try" syntax). They can unlock mutexes, close files, etc. But unlike what you describe, there is no need to put anything at the end of the function: instead, the fact that you have instantiated an object already guarantees that its destructor will be called later. This is called RAII, short for "resource acquisition is initialisation".

<comment><USER18> Yes... RAII is handy, but it doesn't save you from checking EOF logic in my example.

<comment> safety-second You could use a File class that throws on EOF, but that would be a really bad idea for C++ since throw/catch are very expensive.

<comment><USER19> Exceptions are expensive compared to a simple function call, but I imagine they're cheap compared to operations that read from disk. Certainly one exception per file close is not going to hurt.

</comment></comment></comment></comment></comment><comment><USER20> In the article he posts a snippet of F# code:

        type Customer = { Id : string; Credit : decimal option }

        let average (customers : Customer list) =
            match customers with
            | [] -> Error "list was empty"
            | _ ->
                customers
                |> List.averageBy (fun c -> c.Credit.Value)
                |> Ok

And argues that the F# programmer must conclude that all functions may throw because this function accesses the Option.Value without checking that it isn't None first and there's nothing in the type signature of the function to indicate that it may throw.

Is that really how F# works? Similar code wouldn't compile in Rust. You have to handle both cases for Option<T> every time you want the value (or, yes, you _can_ get the value by force, but if you do that, it's definitely NOT an accident and you're basically acknowledging that you want the whole program to crash if the value is None).

Anyway, I'm still in the Either/Result/Try camp. I even used Result/Try types in Java, Kotlin, and Swift (before they officially showed up in Swift and Kotlin).

I think the extra boiler plate in the middle of a function chain is absolutely worth it. I hate the idea that I need to actually read the source code of every function I call from library X just to see if it will throw an exception on me.

Swift has a pretty good compromise, IMO. A function's signature must indicate that it throws, but it doesn't have any type indicated. At least I know when I need to investigate a function further!

<comment> UK-Al05 Thats not how f# works normally.

Normally you chain option operations with either binds, or you do a match(Which is exhaustive).

Directly accessing the value is normally frowned upon.

This guy either needed to make the option type go away, or filter out the None and pass that into average. List.choose could be used for this

        let average (customers : Customer list) =
            match customers with
            | [] -> Error "list was empty"
            | _ ->
                customers
                |> List.choose(fun c -> c.Credit) # Would remove the option type. Any nones would be filtered out the list
                |> List.average
                |> Ok

This is the best I could think off without a computer

<comment><USER21> In support of the article, your code would still throw an exception if all the customers in the list have missing credit.

[https://github.com/dotnet/fsharp/blob/master/src/fsharp/FSha...](https://github.com/dotnet/fsharp/blob/master/src/fsharp/FSharp.Core/list.fs#L627)

You could instead write it as the following to handle that.

      let average (customers : Customer list) =
          customers
          |> List.choose (fun c -> c.Credit)
          |> function
             | [] -> Error "no customers with credit"
             | xs -> Ok (List.average xs)

<comment> UK-Al05 Indeed. I was remembering the behaviour of average off the top of my head.

</comment></comment></comment></comment><comment><USER22> My rule of thumb is: if it is the type of error that I want a stacktrace for: use an exception. For example: programming errors, unhandled cases etc.

If it is an error that I want to handle explicitly, for example by showing a nice user message: use a result type. It is okay to use combinators in this case, but use them wisely.

</comment><comment><USER23> There are actually three error handling paradigms:

1\. Return values, like Either in functional languages

2\. Exceptions

3\. Error handlers, for example Lisp condition system. (Unfortunately, this option became less popular in programming languages, probably because Unix botched it.)

Now here lies the problem. Paradigm 2 is better than 1, because you don't have to handle the error at the caller (or at least, you don't have to unwrap the type). Paradigm 3 is better than 2, because the stack doesn't get unwounded when the error handler gets called - the error handler can choose to continue the original code. Finally, paradigm 1 is better than 3, because it is just so much simpler to set up and reason about.

So it turns out, you're better off using all of them! Although personally I believe exceptions are conceptually wrong, and in almost all cases, either 1 or 3 should be used. (Sadly, option 3 is not well supported in most languages.)

</comment><comment><USER24> eirik's making some very good points regarding the downsides to avoiding exceptions (particularly in the notion that one loses stack trace details and if one doesn't think about how debugging will be done without them, one is in for a world of hurt).

I think I only have some significant disagreement with one observation they've made, which is around runtime errors:

"It's by such misadventure that the working F# programmer soon realizes that any function could still potentially throw. This is an awkward realization, which has to be addressed by catching as soon as possible."

I prefer to think of runtime errors as special case, and I appreciate Go's approach here: Go lacks any exception-handling more complex than panic and recover, and considers anything that is walking the panic / recover path to be an "exception handling failed" scenario. In other words, a correct program should have no runtime exceptions, and if one happens, it should explode as messily, noisily, and identifiably as allowed (and rare is the situation where the correct answer isn't "whole process dumps stacktrace and dies").

My suggestion for the case the author points to is to not catch that exception; if you take a runtime exception you don't anticipate, let it fly. It indicates you're "holding the API wrong" and you want to know about it ASAP, not try to catch around an unexpected failure mode. For _expected_ failure modes, results and error types are often more comprehensible (though the issue of needing to address stacktraces still exists).

<comment><USER25> > In other words, a correct program should have no runtime exceptions, and if > one happens, it should explode as messily, noisily, and identifiably as > allowed

This is not always true. For example if you are writing high assurance software, and the error is recoverable, you really don't want to crash. You want to catch it, log it, and continue/recover execution.

Of course, now you need to make sure that you're not catching an exception that is not recoverable.

</comment></comment><comment><USER26> The title contrasts the last paragraph. I believe the author means this to be true only in the CLR, F# specifically.

> I strongly believe that using result types as a general-purpose error > handling mechanism for F# applications should be considered harmful. > Exceptions should remain the dominant mechanism for error propagation when > programming in the large. The F# language has been designed with exceptions > in mind, and has achieved that goal very effectively.

</comment><comment><USER27> Exceptions in Haskell are unavoidable and awful. If you want to write code that responds to the errors that could occur, even some of them, you basically have to read the library source because they're completely undocumented in many libraries - even in the standard library (try something exotic like, um, reading a file). And that means you need to know your whole stack.

If they were at least declared in the type so the compiler could give me a warning.

<comment><USER28> That does suck, does it commonly occur because of non-total functions in the libraries or what?

</comment></comment><comment><USER29> I wrote something in that vein, in which I defend checked exceptions (in contrast with unchecked exceptions):

[https://norswap.com/checked-exceptions/](https://norswap.com/checked- exceptions/)

> Summarized: people don't want checked exceptions because they are going to > be abused by lazy programmers.

<comment><USER30> There is also a long discussion on pros and cons of checked exceptions here: [https://email@example.com...](https://firstname.lastname@example.com)

</comment></comment><comment><USER31> In Java, you can pre-allocate static final Exception objects with a pre-filled stack. These exceptions have much better performance characteristics [1] and are used by Netty [2] for control flow purposes. Sometimes these are helpful and the performance is good, but only when you don't need a full stacktrace or to customize the error message.

[1] [http://normanmaurer.me/blog/2013/11/09/The-hidden- performanc...](http://normanmaurer.me/blog/2013/11/09/The-hidden-performance- costs-of-instantiating-Throwables/)

[2] [https://github.com/netty/netty](https://github.com/netty/netty)

</comment><comment><USER32> Reminds me of this classic

enum Bool { True, False, FileNotFound };

<comment><USER33> What you really need in such cases is a pentastate boolean:

[https://crossdysfunctional.tumblr.com/search/pentastate](https://crossdysfunctional.tumblr.com/search/pentastate)

</comment></comment><comment><USER34> Can't the rethrowing logic be expressed using `fmap`?

        λ :set -XTypeApplications
        λ :t fmap @ (Either Error)
        fmap @ (Either Error) :: (a -> b) -> Either Error a -> Either Error b

</comment><comment><USER35> I don't think it should be "exception vs returned value".

First, if you are using a dynamic language, then exceptions make sense. You want to get there quickly, not handle every corner cases.

At the opposite spectrum, if you are writing rust, of course you want something very explicit and extremely aggressive to deal with errors.

They just serve different needs.

Also, exceptions don't have to be implicit, difficulties arise when the code you are using do not or cannot declare what can of exception can happen when you call it.

But if the language let you declare all the stuff you can raise, then there is not much difference.

</comment><comment><USER36> Good article but it is tangential to a basic design issue.

Error handling should be done at the edges of systems rather than in the center. If you do that, it doesn't matter whether you use exceptions or error monads, you have a pure core that doesn't need to deal with error handling and a very slim area to catch errors. The mechanism you use for error handling, at that point, doesn't matter.

The problems of error handling often come from having it spread across the system and mixed with the logical flow.

<comment><USER37> it's not trivial in every domain to distinguish between pure and non-pure operations. If you're writing software for control systems, robotics, anything that has a very tight, low-level coupling between programming logic and the outside world it's harder or often not possible to separate concerns into some sort of data -> logic pipeline that lends itself to this style of programming, or it may come at the cost of performance.

<comment><USER36> It's a decent goal, though. For all else, there's Erlang.

</comment></comment></comment><comment><USER38> > ...exceptions-as-control-flow abuse or even the assertion that exceptions > are really just a type safe version of goto.

I was recently telling someone about a little-known Java feature that I wish C would adopt. Goto is common in C exception handling code because the alternative is unworkably messy. Java has named code blocks that you can break out of, so they're not gogo, but they're also not exception abuse.

        initBlock: {
          if (fail) { break initBlock; }
          doSomething();
        }

<comment><USER27> In that case, in javascript, i always just write a function.

        {
          init()
        }

        const init = () => {
            if (fail) return
            doSomething()
        }

(there's a few other cases i introduce functions for syntactic reasons in js - e.g. at the expense of a const funtion, i can convert a let to a const - but i have always found this improves the code on standard readability guides)

</comment></comment><comment><USER39> I think it's fine to use exceptions as error handling if the stack can safely be destroyed with that exception. As the article states, they provide a lot of information to help debugging and are resilient to refactoring. An example of safe stack destruction is a web service call that cannot complete because of the error. You're going to return an error response regardless.

I don't think exceptions should be used if they are caught and then retried or transformed. I don't think exceptions should be used in library code, except of course for unanticipated behavior such as hardware or network problems. In these cases it's better to use a result object, which better forces the library consumer to inspect what is being returned, rather than pass on what is returned and (maybe?) handle exceptions on errors. Ideally the library catches unanticipated errors and never throws, but those are edge cases that are probably not worth the investment by the library maintainer to handle. Development effort across the ecosystem is probably minimized when library consumers handle exceptional situations themselves, which they may have more insight into if their own infrastructure is causing the exception.

</comment><comment><USER40> I love using exceptions as control-flow, Python makes it very easy, and it's really helpful.

edit: grammer

<comment><USER24> Many of the problems that people who eschew exceptions are trying to avoid or fix, Python simply shrugs and declares isn't a problem. If the software you're writing agrees with that assertion (which it probably does if you're writing Python with no static type annotations and no pass through mypy or a similar tool to verify those type annotations are sound), you're fine.

Unfortunately, when you _do_ eventually find yourself in a place where you have to care (which is the fate of any codebase that becomes large or complex enough), Python actively hinders making reliable code that is easy for strangers to modify without introducing subtle bugs.

<comment><USER41> Can you please elaborate on those problems ? Personally I believe exceptions are the worst way to handle errors, except for all other ways.

<comment><USER24> Python's soft static type rules and extremely flexible variable instantiation unfortunately turns every line of code into a potential runtime error, because the code can't know at compile time if a variable was introduced to the global context that could bind to any given name. Typos are therefore deadly at runtime in Python in a way that they fundamentally aren't in other languages; if you try to write

foo = 0

if foh == 1: # oh no, I misspelled the variable

... many languages (including F#) will fail to compile the program because 'foh is uninitialized.' Python can't know if 'foh' is intended to be a global variable and so will execute the program and only determine while evaluating that line that 'foh' doesn't exist. This is especially insidious in error handling, where the error codepath isn't necessarily exercised; essentially, Python's flexibility implies that if your unit tests don't have 100% line coverage, you can't even know if your program is basically devoid of simple variable typos naming never-existing variables (a check most languages give you for free).

In a language with that feature, a rich ecosystem of exceptions is almost necessary, because _every line of code could hide a runtime exception!_

<comment><USER41> Maybe I am missing something but I think every dynamic typing system has this problem. I can't see what this has to do with Python and exceptions in general. It is not like there aren't statically typed languages with exceptions. This comment is an excellent critique of dynamic typed systems but it has nothing to do with exceptions.

<comment><USER24> The top-thread post was referencing Python, so I'm speaking in the Python domain specifically. Other dynamic languages have this problem also, and other languages with stronger static type guarantees do support exceptions.

I haven't encountered a language with dynamic typing of the sort Python has that doesn't also have a robust runtime exception system, and it'd be interesting to see what that looks like. There's probably some old flavors of BASIC that fit that mold (i.e. variable declaration is not required and also the only thing it offers for exception handling is setting a label to GOTO if a runtime exception occurs).

<comment><USER41> I guess I was too fixated on the exceptions part of your comment. You are right that due to Python's dynamic nature every line can turn into a runtime exception. Maybe it's because English is my second language but I couldn't understand that in your first comment.

</comment></comment></comment></comment></comment></comment></comment><comment><USER42> I've pushed for Either[L,R] based coding without exceptions for a while and met a lot of criticism along the way. I still think it has value over exceptions but this post does bring up good points. The one about throwing the stacktrace away is annoying, but with Future your stacktrace is useless anyway. We have a system where every error has a unique id that looks like a jira ticket number so you can find the source very quickly and avoid the stringly typed error.

This section of code is what i want to avoid:

        user = service.getUser()
        bill = billingService.getBill(user)
        notificationService.message(user)

we use the same http client in all underlying service clients. let's say you get to the end of this block and it results in SocketTimeoutException. How do you know what call did this? you would have to add to every line:

        .recoverWith({case t => new Exception("billing exception", t})

to propagate the context up. Either forces you to handle that well and write the context.

a lot of it comes down to style choice because you could do it with exceptions, but i think this makes it easier not forget cases because the compiler will tell you

</comment><comment><USER43> Here's my problem with exceptions:

(I'm going to treat checked exceptions same as unchecked, because you don't _have to_ use checked or they can be trivially broken by using the Exception superclass)

At the beginning you often take shortcuts and ignore error handling in order to get the happy path to work. Once it is working, it is very easy to overlook some exceptions that should be handled, leading to unexpected runtime errors.

Using the Result monad (say in Rust), you can easily just add .unwrap() after any call that produces a Result to get the happy path working. After you're done with that, its easy to find all the places you took shortcuts and fix them.

To me, the ergonomics of a language is exactly this gap between how concise the "take all the shortcuts" code is and how easy it is to transform into production code where all the possible error states are properly accounted for.

</comment><comment><USER44> I personally feel that use of exceptions kinda depends on how compiled the language is. With strongly-typed, compile-checked code, it's only really bare assertions for a test suite to build. Meanwhile in weakly-typed languages without means for overloading, certain type-based errors have to be made to ensure the signatures are met.

Errors for trivial things (ie control flow) are an unfortunate abuse of try and catch; generally exceptions should only be thrown to users of an external API, not an internal one. If an exception is caught from the same layer of abstraction it was thrown from, it's a very leaky abstraction — as opposed to, say, a regex parsing error, which ensures the abstraction isn't implicitly failing.

</comment><comment><USER45> So much confusion between Exceptions and Errors in this thread. Exception abuse is for bad code that needs to return early, because they have no pattern matching, like Java and JavaScript. Nice languages have error handling, think Go, Elixir, Rust, Scala.

</comment><comment><USER46> Interesting article, also very F# specific.

A similar approach with type aliases (to be moved to value objects or structs with behaviour aka rich models) in Rust.

```rust type Amount = u128; type MoneySign = Option<Sign>; type Precision = u8; type CurrencyIsoCode = &'static str; type CurrencyName = &'static str; type Currency = (CurrencyIsoCode, CurrencyName); type Money = (Amount, MoneySign, Precision, Currency); type Balance = (Money); type ExpirationDate = &'static str; type MoneyWithdrawalError = &'static str;

enum MoneyWithdrawalResult { Success(Money), InsufficientFunds(Balance(Money)), CardExpired(ExpirationDate), UndisclosedFailure(MoneyWithdrawalError), } ```

</comment><comment><USER25> I'd say this works in Erlang because it is part of the culture, but in java or python what I've seen mostly is people forgetting to catch exceptions, or not being able to pinpoint where exceptions are catched.

<comment><USER28> Erlang has a very different execution model compared to those other languages you mentioned. In fact, Erlang's culture in many ways encouraged to program less defensively than you would be expected to in other languages (ever heard of "let it crash"?).

That's because the whole expectation of exceptions/errors is built into the system unlike pretty much anywhere else.

</comment></comment><comment><USER47> What's exception handling actually doing internally?

Genuinely interested and i need to know.

Must be some kind of "goto catch block" internally when you throw an error. It has to stop the execution and jump somewhere, but that somewhere is set in the code where it catches the error.

If you're calling a function then that function throws an error, it has to prematurely exit to _somewhere_ so there must be a stack of the locations of the catch blocks or something? That then unroll as you exit the try/catch blocks as well.

<comment><USER48> For gcc/clang C++, internally, it will unwind the stack until it finds a handler. This way it doesn't have to do anything at the moment of setting a handler (i.e. "try" in the underlying code), as a trade-off it's relatively expensive to throw an exception. But note that C++ standard does not specify this, so it's fair game for compiler to do anything. E.g. it can use long jumps, or just dispatch different functions based on all possible exception states (which produces very large binaries).

<comment><USER47> Thanks for that, nice to know!

</comment></comment></comment><comment><USER49> It's almost a meme at this point, but the solution, of course, is algebraic effects. Among other things they let us implement checked exceptions, but in a sane way that's safe without requiring the annotation of every single function.

[https://www.microsoft.com/en-us/research/wp- content/uploads/...](https://www.microsoft.com/en-us/research/wp- content/uploads/2016/08/algeff-tr-2016-v2.pdf)

</comment><comment><USER50> While my favorite language (Erlang) has Exceptions, I really like the "let it crash" model -- let the whole light-weight thread die and have the controlling thread (a/k/a "supervisor") figure out what to do.

I've seen insane Java programs where tracking how many layers up Exceptions are caught was mind-twisting. And conversely, when everything was wrapped in a try/catch and then, essentially ignored.

</comment><comment><USER51> I wonder how many commenters clicked on this link because this really has nothing to do with "exceptions" (as in the things you raise or throw) at all. So it's a fairly terrible title that is really arguing against a catch-all Error case.

The one parallel to (actual) exceptions is the author is arguing for a constrained subset of error states rather than a catch all Error type. This isn't a new idea. Java essentially does this with checked exceptions. C++ does this where you can declare what exceptions can be thrown (which you should basically never do).

So I did Java for years. Java had several Grand Experiments, one of which was checked exceptions. Despite it still having some fans I think the general consensus now is that checked exceptions were a Huge Mistake [tm] for many reasons (eg leaking implementation details, cluttering your API the whole way up).

One anti-pattern I see with exceptions is people using them for control flow. For example, dealing with a ParseException in Java when parsing numbers [1].

This of course falls into a religious argument about what an exception actually is.

For a few years at Google I wrote Google's flavor of C++, which I actually grew to really like. It is pervasive that any method in Google C++ returns a util::Status. This is much like Go error handling but (IMHO) better.

For one thing, it's a compiler error to ignore the result of a util::status (you can call .IgnoreResult() if you really want to ignore it). I think this is a much nicer and safer default.

You return things with a util::StatusOr templated union type that has the same semantics. There are even macros (that were somewhat controversial) to reduce boilerplate to do things like call a function that returns a StatusOr, assign the result to a variable if it's OK or return the error if it's not.

There are of course utility methods for adding context to a Status(Or) you're returning.

So all this came about because Google C++ strictly prohibits exceptions. This is a historic decision that's probably impossible to unwind at this point and honestly I don't think there's a strong motivation to change it.

IMHO exceptions are a false economy.

This is one of many things I like about Rust. Rust's enums are kind of the next evolutionary step for this. It's a compiler error not to deal with all options, there are constructs to reduce boilerplate and you can pass values.

[1]: [https://stackoverflow.com/questions/8286678/parse-string- int...](https://stackoverflow.com/questions/8286678/parse-string-into-number)

<comment><USER52> I think Java's flavor of exceptions are especially horrible, as you mentioned a string->int parse failing is typically not exceptional at all but rather expected. However, I do think there is a place for exceptions: exceptional situations.

Status(Or) is nice for certain types of errors, but now if you want to correctly deal with out-of-memory errors that means every single function that allocates anything on the heap now needs to return a Status(Or) in case the allocation fails. That error message then needs to be propagated through your entire library back to wherever it is that you can handle memory errors, which is likely somewhere at the root of the library. That now means that every single function in your entire library needs to return a Status(Or) and propagate it, which significantly bloats your codebase.

The macros you describe likely help with that somewhat, but then those macros are basically manual exceptions in that they just unroll the stack to where you don't call the macros anymore, but they require a bunch of extra manual effort and obfuscate your code somewhat. They are also slower in the common case (no memory errors), as you are now performing an extra check on every single function call in your entire library.

Meanwhile using exceptions together with smart pointers and smart locks basically makes it so that you can handle memory errors "for free" without having to bloat your codebase. When a memory error pops up, throw an exception and unroll back to where you can properly handle the memory error. The smart pointers/smart locks/destructors will take care of cleaning up everything. No need for any extra checks all over the code base for such a rare error.

</comment></comment><comment><USER53> As someone who's been writing Go for too long, way too long, I agree.

Handling errors everywhere seems to always become ad-hoc exception handling. Oddly, the apologists call this "syntactic sugar for avoiding repetitive error handling", still can't wrap my head around that one.

</comment><comment><USER54> The real problems with exceptions are that _they have a large performance overhead,_ and that they differentiate poorly between anticipated errors and truly exceptional situations.

The performance overhead comes from grabbing a stack trace and constructing an object that lives on the heap, and then unwinding the stack. (Some assembly experts can probably explain this overhead better than I can.). When your code handles an error condition that it anticipates, that overhead is wasted CPU cycles.

(This is why Exceptions aren't for flow control.)

What we really need are languages that differentiate better among success / error / exception. Go has panic / resume, and Java has compiler-enforced exception handling, unless it's a runtime exception.

What I want instead is something where I have optional and convenient syntax to handle lightweight errors; or the ability to automatically convert errors to exceptions if I don't handle them.

TLDR:

Think of the query to lookup a record by ID case. If the record isn't found, it's an error that doesn't have a stacktrace or an object on the heap. But, if my code doesn't handle the error, then it's a full exception with a stacktrace.

<comment><USER55> Exceptions don't _generally_ have a large performance overhead, they do in C++. Ocaml exception handling for example was orders of magnitude faster last I looked. And C++ itself is seeking to fix the super-slow design: [http://www.open- std.org/jtc1/sc22/wg21/docs/papers/2018/p070...](http://www.open- std.org/jtc1/sc22/wg21/docs/papers/2018/p0709r0.pdf).

</comment></comment><comment><USER56> i think there is a distinct difference between an exception, and a recoverable error.

Result is not intended to be used for exceptions, but rather recoverable errors. There are a number of situations where I have used Result to recover from an exception that was expected, but it would be folly to try to handle all error paths (especially with runtime errors).

I think the author is trying to convey the point that we shouldn't use Result as a catch-all, but rather as a means of conveying possible known error paths for a function. There will always be the possible unknown error paths, which are handled by the runtime's exception handling/reporting.

</comment><comment><USER57> I theoretically like exceptions, and used to extol their virtues, but I've come to hate them in practice. They're an endless source of fustration in that the APIs you least expect will throw various unexpected exceptions for various undocumented edge cases, which invariably leads to heisenbugs crashes in our bug tracker that I need to go waste a few hours trying to repro and root cause because I, foolishly, was a good boy who didn't spam catch(Exception) everywhere (as that would also catch the null/index exceptions indicating real bugs). Theoretically, forcing you to use checked exceptions would solve this, but would defeat many of the supposed virtues of exceptions.

I also frequently get stuck refactoring a lot of code other people have written because an exception tried to unwind across an ABI boundary, and nobody thought about how to handle that or what would happen. That ABI could be across a C module, which has no exceptions. Or perhaps across a C++ module built without exceptions, or using an incompatible unwinding mechanism. Cleanup gets skipped, undefined behavior gets invoked... it's a mess.

So, invariably, I write some catch(Exception) equivalents, if only to manually write the code to explode loudly and in a way condusive to debugging, instead of much later when the stack trace has been mulched through rethrows, or access violations from the UB, or ...

Now compare and contrast that to error codes, which I theoretically dislike, but swear by in practice.

Error codes are C ABI safe, any language can return them, set them, or store them. They're part of the method signature, neglected documentation be damned. There won't be any exotic failure modes where C++ destructors get skipped due to a setjmp style unwind. Even the absolute worst APIs usually have _some_ kind of incomplete list about failure modes - a list of constants somewhere - and I have a fighting chance of deciding upon a sane local fallback (on top of breakpoint/logging/reporting) in the event of an undocumented/unexpected error code.

My biggest concern was always accidentally ignoring an error code, but every language at least has compiler extensions these days - to mark a function result as needing to be used - and a way of turning that warning into an error. Does this sometimes lead to a little extra error handling boilerplate? Yes. Does that even enter into the top 10 issues I have with error handling code? No.

I do get the occasional bug where ignoring an error code contributed to it's occurance, but those are a small price to pay compared to avoiding all the bugs arising from exception (mis)use I avoid.

</comment><comment><USER58> For the readAllText example, could it return Result<string, Exception>?

<comment><USER59> Yes, but you can still argue just throwing it might be better. This also affects the stack trace, because, at least in C# (so probably F#) `throw ex;` is different than `throw;`, which rethrows the exception as if it weren't caught.

</comment></comment><comment><USER60> I completely disagree with this article, as it makes a lot of claims which are not true, uneducated or intentionally misrepresented to make a case for exceptions:

> Because runtime errors are difficult to anticipate, I claim that using > result types as a holistic replacement for error handling in an application > is a leaky abstraction.

Yes this is true, but it's not a leaky abstraction. There's always the posibillity that shit hit the fan and something happened which was unexpected and indicates an unhealthy system in which case it will result in an unanticipated exception such as a RuntimeException.

This is ok, that's why every application has somewhere a global error handler, which can capture that unusual exception, log it and potentially terminate the application or put it in an unhealty state so that a higher level scheduler can replace or re-start the app. Possibly even raise some emergency alerts with developers via PagerDuty, etc.

However, it most certainly doesn't leak anything or makes the Result type less useful, because most application errors are anticipated due to a combination of user inputs or other external factors such as API calls and these can be perfectly handled in a more predictable way by using a Result type.

> It's by such misadventure that the working F# programmer soon realizes that > any function could still potentially throw. This is an awkward realization, > which has to be addressed by catching as soon as possible.

Not really. There's nothing awkward about a runtime exception. Shit sometimes happen. And it's not true that it has to be handled as early as possible. As said before, you only have to deal with exceptions in a global error handler. If the error must be caught as early as possible, then it means that there is a possible plan B and a possible plan B can only exist if the error is anticipated. If it is anticipated then it should be returned in a Result type. So fundamentally exceptions are not awkward. When they happen there's exactly only one place where they need to get handled and the rest of the application code just works with Result types where errors are possibly known.

> In the majority of codebases using result types that I've been reviewing, > people typically just end up re-implementing exception semantics on an ad- > hoc basis. This can result in extremely noisy code...

So he has just worked with badly written code. If all the code is doing is bubbling up an error from the Result type then whats the point of returning that error? Return errors which are meaningful and where the calling code can deal with it immediately, otherwise don't bother.

> An important property of exceptions -which cannot be stressed enough- is > that they are entities managed and understood by the underlying runtime, > endowed with metadata critical to diagnosing bugs in complex systems. They > can also be tracked and highlighted by tooling such as debuggers and > profilers, providing invaluable insight when probing a large system. By > lifting all of our error handling to passing result values, we are > essentially discarding all that functionality.

Well as said before, the Result type is not to be logged or thrown or something. It's there so calling code can deal with it - implement some sort of plan B. If all the author wants is to always log the entire exception including stack trace for every error and not really deal with it then fair enough, just use exceptions everywhere, but that application will suck big time.

> That said, I strongly believe that using result types as a general-purpose > error handling mechanism for F# applications should be considered harmful.

Functions are Input -> Output. If you don't like that as a "general" mechanism, and you prefer Input -> Output, Exception, {whatever} then use OOP and not FP. It almost seems like that the author just doesn't like the functional appraoch in functional programming, which is a weird point to make.

> Exceptions should remain the dominant mechanism for error propagation when > programming in the large.

Based on which logic? That's such a generalisation that it's just plain wrong. Exceptions are try-catch error handling and there is no proof that try-catch is the ultimate error handling solution. Lots of new languages make an effort to exactly not do that, so where's the evidence?

<comment><USER61> >Return errors which are meaningful and where the calling code can deal with it immediately, otherwise don't bother.

Don't bother and do what?

And how do you know what the calling code can and cannot do?</comment></comment>


Django + Bootstrap 3 - <AUTHOR> https://github.com/dyve/django-bootstrap3

<comment><USER2> I always use django-crispy-forms for my projects, and it has support for bootstrap3 too.</comment>


Ask HN: Any ideas for a better term than "Crowd Sourced"? - <AUTHOR>

I can't stand the sound of the term 'crowd sourcing', however the meaning that we all seem to grok is very useful and important.<p>'Crowd sourcing' sounds very technical and cold. Crowd... negative connotation... Sourcing... very robotic.<p>Just wondering if anyone has come across any other phrase that can evoke a similar concept with a more fluid and human feel? <comment><USER2> what is the negative connotation with crowd? if it was herd sourcing i could see the negative connotation- with crowd not so much except when use along the lines of "i don't follow the crowd". still that use of crowd is spot on for what crowd sourcing is- following the crowd.

<comment><AUTHOR> i think a crowd ...as in crowded. busy, jammed, confining.

</comment></comment><comment><USER3> I also hate UGC as a term - user generated content - again sounds very robotic, not fun or engaging...

</comment><comment><USER4> Collective, mass sourced?

</comment><comment><USER5> Community Generated?

<comment><AUTHOR> I like this only that it does not somehow capture the aspects of 'crowd sourced' that suggest that certain content will rise to a more visible status based on the activities of the community.

So "community sourced" might be a definite step in the right direction. Still wouldn't mind replacing the sourced part ... if possible.

</comment></comment><comment><USER6> The Wikipedia article on crowdsourcing suggests both "community-based design" and "open call". You might consider perusing the rest of it for other ideas.

Excerpt:

 _Crowdsourcing is the act of outsourcing tasks, traditionally performed by an employee or contractor, to a large group of people or community (a crowd), through an open call.

For example, the public may be invited to develop a new technology, carry out a design task (also known as community-based design[1] and distributed participatory design), refine or carry out the steps of an algorithm (see human-based computation), or help capture, systematize or analyze large amounts of data (see also citizen science)._

<http://en.wikipedia.org/wiki/Crowdsourcing></comment>


Linear Regression - <AUTHOR> https://www.simonwardjones.co.uk/posts/linear_regression/ <comment><USER2> This article had a brutal leap from being aimed at someone with barely any understanding of maths (complete with friendly emojis) to use of cost functions (without any explanation) and associated code. It's bit like the "how to draw an owl" meme.

A good article on linear regression, in my opinion, would break it down into three steps:

1\. Spend a bit of time looking at cost functions. In principle linear regression is finding the "best" line, where by "best" we consider all possible lines (yes, all uncountably infinite of them), compute the cost function for each one, and pick the one where the cost comes out lowest. You want to show a few example lines on top of some example points and label their costs. Start with absolute deviation (i.e. l1 norm) to start with - let's face it, that's _really_ the most obvious cost function if you don't already know what comes next - then contrast with least squares (i.e. l2 norm). For example, note that least squares cost function "cares" more about points that are a particularly long way away.

2\. Admit that, OK, we do want an algorithm more sensible than "try every possible line, labourously computing the cost of each one". Now you can talk about gradient descent - and I mean WHY you use gradient descent, not the computation. And now you can mention that least squares is differentiable, so solves nicely for gradient descent, which is the real reason we tend to prefer it over absolute deviation.

3\. Finally, after both of those you can solve the gradient descent equations and show some associated code.

<comment><AUTHOR> haha - I love the use of the word brutal here! It is a brutal leap.

I wanted to give the ideas in the simplest way with friendly emojis and then go onto the more complex derivation with the cost function etc. I haven't explained the idea of the cost function enough. I think your idea for stating with the cost function (as a concept - not a formula) and absolute error may have been nicer to be fair. I can see a nice d3 visual where you can slide the gradient and see the total error change!

I could always add the line of best fit approach and more intuition for the cost function after I introduce training data (and before the brutal leap)?

<comment><USER3> I'm very much _not_ a fan of this introduction.

You use gradient descent, but do not introduce the normal equations. This is problematic for at least two reasons.

Case 1: Design matrix has full rank

Omitting the normal equations obfuscates what is really going on. You are inverting a matrix to solve the first order condition of a strictly convex objective, which therefore has a unique optimum.

Case 2: Design matrix does not have full rank

Omitting the normal equations hides the fact that there are _multiple_ solutions to the first order condition. Gradient descent will find one of them, but you need a principled method for selecting among them. The Moore- Penrose pseudo-inverse method gives you the solution with the smallest L2 norm.

Omitting these details is setting learners up for failure.

<comment><USER4> I agree with this 100%.

You may amused to learn that "How would you program a solver for a system of linear equations?" was an informal interview question for a top machine learning PhD program, and applicants were not looked upon favorably if they mindlessly gave gradient descent as an answer.

</comment></comment></comment></comment><comment><USER5> Two comments here, and I am sorry if they come across as mean:

1) I know this article isn't aimed at me, but I do truly hate the excessive emojis.

2) More substantively: not once does the word "statistics" enter here. There is not a single illustration of the _idea_ behind linear regression, which is staggeringly simple: it is just finding the best linear fit. Anyone who looks at a 2D scatterplot can do an approximate linear regression with their brains by visualizing a line that sorta fits the data. While the gradient descent stuff is useful for extending a machine learning algorithm, introducing linear regression this way obscures the actual concept - and indeed, obscures what machine learning actually is.

In my experience there are a huge number of data scientists who are ignorant of statistics and don't understand their models and algorithms. Although this is unfair, it is my impression that the author himself does not understand linear regression, even if they are able to write formulas using vectors. This article does a disservice to learners.

<comment><USER6> > I do truly hate the excessive emojis.

I am more in the camp of actually always finding them excessive. Especially in more serious, and possibly, interesting posts.

<comment><USER7> I would have loved to believe that they are a fad and will pass away, but I just found myself using them in the same way that I used to use phpBB emoticons.

I think they're never going to go away, but at least we can try to eradicate them from professional discourse and education.

<comment><USER8> The homebanking login page from my bank greets me with "Hello :) How can we help you today?" and it makes me cringe _every time_. This is a major bank by the way.

I do use smileys here on HN, on facebook, and chatting, to signal I'm being friendly and non-confrontational, to preempt and defuse situations which could escalate into anger if someone misreads the tone.

</comment></comment></comment></comment><comment><USER9> If you enjoy these kinds of explanations, "Data Science from Scratch" by Joel Grus explains many machine learning algorithms and has you implement simple versions of them in Python as you read along. It also covers linear regression and I wonder if that book is where the author got the idea for this series of blogposts. Kudos anyway.

Something of a nitpick, but one thing that both Simon Ward-Jones and Joel Grus miss is that linear regression is typically not implemented using gradient descent at all, there's an analytical solution and you can get the beta coefficients with straightforward matrix algebra. It's much harder to explain than gradient descent so I get why they don't bother, but on the other hand without that background it's hard to see why everybody talks about _linear_ regression all the time when with gradient descent or any other numerical optimizer there's really no limit to what f(x) can look like.

<comment><USER10> I don't think they've missed the fact that for linear regression there's an algebraic solution, but machine learners typically treat linear regression a simple special case, and as soon as want to go a bit beyond you have to go with an iterative numerical optimizer anyway so why bother with the special case solution.

My main criticism on the article would be that the nitty gritty section only makes sense to a reader that has already done a linear algebra / multivariate calculus course. In which case they've likely already covered least squares in greater depth (including the exact solutions) than this article. So I don't really see the purpose of the math section, except maybe to signal that the writer has a descent understanding of the algorithmic detail.

</comment></comment><comment><USER11> The discussion here suggests that a lot of developers are jumping right into the middle of data science from a machine learning perspective without a solid understanding of what I would call basic math. It's a lot easier to succeed and compete with a solid grasp of linear algebra, calculus and numerical methods. My personal experience is that curriculum takes a good couple years to really get your head around.

For my current project I had to really understand the closed-form solution for linear regression and even it looks straightforward on paper it really took a while to sink in.

</comment><comment><USER12> Why do people write or even read posts like this. You can crack open any stats textbook and it will be explained there in much more detail by someone likely far more qualified to be talking about it.

Feels like some mix of SEO-farming/resume-building-blogspam.

</comment><comment><USER13> Why is it going from zero to gradient descent solution? I feel like going from zero to deterministic matrix inversion solution would be more normal.

<comment><USER14> Yes. In fact, an even better solution would be using QR factorization...

</comment></comment><comment><USER15> If you've got an interesting nonlinear cost function to minimise and can compute the gradient, you can do a lot worse than plugging the thing into L-BFGS-B and letting it optimise it.

e.g.

[https://en.m.wikipedia.org/wiki/Broyden%E2%80%93Fletcher%E2%...](https://en.m.wikipedia.org/wiki/Broyden%E2%80%93Fletcher%E2%80%93Goldfarb%E2%80%93Shanno_algorithm)

[https://docs.scipy.org/doc/scipy/reference/generated/scipy.o...](https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.fmin_l_bfgs_b.html)

What'll that give you compared to a simple gradient descent? It'll attempt to accelerate convergence by estimating an approximation of the Hessian matrix - all the second order partial derivatives, and use a line search algorithm to figure out a good step size for each step instead of using an arbitrary constant step size aka "learning rate". The "L-" variation of the algorithm will use a limited amount of memory when approximating the Hessian matrix, which might help if your cost function has a larger number of parameters. The "-B" variations of the algorithm will also let you set upper and/or lower bounds on each variable that will be respected during the search.

</comment><comment><USER16> > If you're interested read on, if you're not, see yourself out.

Huh? Doesn't this apply to literally every piece of writing ever produced? The reader is always free to leave.

<comment> globular-toast The author wanted to use the door emoji.

</comment></comment><comment><USER17> This is one of the most condescending things I've read in years

<comment><USER18> Yeah, I get the impression this is article is more to show off how smart the writer is, rather than about effective instruction. If you can actually read the article, you have no need for the content because you've probably encountered gradient descent already in your maths training (or could figure it out).

Also, there's no concrete examples of this algorithm in place for students to go through and built intuition and a working understanding. Even the most dense math text books I've read have problems for the reader to work through.

</comment></comment><comment><USER19> > Regression is any algorithm that takes a collection of inputs and predicts > an output.

I get that the author is writing for a certain audience, but this is a gross over-simplification.

<comment><USER20> Depends on the tradition you are coming from. In machine learning it really is just that. A synonym for continuous-valued function approximation based on training data.

You may say it's only regression if it fits your favorite framework, like giving confidence values or goodness of fit etc, but that's not true in general. There so many variants, like Bayesian probabilistic regression, nonparametrics, neural nets, random forests etc.

<comment><USER21> It's a nonstandard definition at best. While regression is a name given to some algorithms (linear and logistic for example), this is an artifact of the statistical foundations of ML. Its standard use in ML is to describe the problem, not the solution: regression is predicting a continuous value and classification is predicting discrete categories.

Either use is ok, but e.g. a tree model predicting if an animal is a dog or a cat is not regression by any definition.

<comment><USER20> I'd say arguing about this is a huge distraction. Some would say classification is a special case of regression: the predicted continuous values are interpreted as class probabilities.

You're right that regression is a type of task, not a type of solution. The conceptual difference is important to understand if someone does not yet know it. But it's not an all or nothing set-in-stone thing. It implies there is a waterfall design to these ideas, as if some oracle posed these tasks to us and then we started finding solutions to each of them separately. But actually in many cases one and the same algorithm with small tweaks can tackle multiple tasks. Sometimes we have the hammer (algorithm) first and then the nails (task).

How you build your taxonomy and how you categorize one approach or another is not the same as learning and understanding. I always had an issue with this at university, where some lecturers would confuse learning lists like "what are the 3 areas of field X" or what are "the 4 principles of approach Y" etc.

The world is not structured according to subjects, fields, subfields etc. It's not a single hierarchy, but a big mess of similarities, like a graph or a multidimensional space. The map is not the territory and so on.

Terminology is necessary of course for communication and structuring books etc, but I like to see it merely as a utilitarian thing. The categories provide a scaffolding so that learning can happen. Studying the vocabulary and various outlines and nested hierarchies is a useful part of the journey but should not be confused with actually learning the thing itself. You could in principle learn all about regression without ever learning the word "regression".

The name actually originates from statistics, named after the "regression towards the mean" phenomenon, where they observed how the adult height of people is closer to the average compared to the height of their parents. So a tall person will have tall children but less extremely tall (in tendency, some will of course be even taller). So confusingly, regression literally means "going back".

</comment></comment></comment></comment><comment><USER22> Now, posts full of emojis that use gradient descent for a classical problem with an efficient analytical solution ([https://en.m.wikipedia.org/wiki/Linear_least_squares](https://en.m.wikipedia.org/wiki/Linear_least_squares)) that you learn of in any ML class make it to front page...

</comment><comment><USER23> Why go through all the steps of deriving gradient descent when there is an analytical formula to get the estimate of the parameters ? Maybe I guess to scale up in big data contexts? But the analytical solution in my opinion gives more insight to the problem than the gradient descent solution

</comment><comment><USER24> I would prefer an introduction via the Moore-Penrose Pseudo-Inverse. It's a lot easier, imho

<comment><USER25> Introducing linear regression with gradient descent can also be really confusing for a newcomer. Gradient descent solves a problem (nonlinear optimization) which does not exist here.

</comment></comment><comment><USER26> This is one of the rare articles which applies linear regression to something which is linear by nature (I am assuming good faith from the authors when they use "intuitively" to mean mean "we know our model is linear because <something>")

Whenever I look at generic information (news, newspapers, generic articles), someone is taking a cloud of points and, bam!, draws a straight line through them. I actually reached to some authors to ask why they did that.

Answers (if any) were varied, I had I think one person who actually said that the data is expected to be linear. Many could not see the point, up to "if it looks like a line, then we put a line".

</comment><comment><USER27> Great article ! But I must admit, I didn't expect it to be using gradient descent. I like the Wikipedia derivation as well [1]. It says that the minimization problem is convex, so you'll find a global minimum with gradient descent. But more interestingly, at the cost of inverting a potentially huge matrix, the article presents an elegant analytical solution to the problem.

[1] [https://en.wikipedia.org/wiki/Ordinary_least_squares#Matrix/...](https://en.wikipedia.org/wiki/Ordinary_least_squares#Matrix/vector_formulation)

</comment><comment><USER28> The next level:

[https://en.wikipedia.org/wiki/Symbolic_regression](https://en.wikipedia.org/wiki/Symbolic_regression)

<comment><USER29> Do you have personal experience with Symbolic regression? If yes, please share them briefly. What are advantages and disadvantages in comparison to other predictive algorithms? Did it showed to you better results than other predictive algorithms?

</comment></comment><comment><AUTHOR> Explanation, maths and code

<comment><USER30> Well done. I look forward to digging into this more this weekend.

<comment><USER31> You might prefer this [https://faculty.marshall.usc.edu/gareth- james/ISL/](https://faculty.marshall.usc.edu/gareth-james/ISL/)

</comment></comment></comment><comment><USER32> Why is he using gradient descent? There's a closed form expression for the coefficients.

</comment><comment><USER33> To me it seems that the concept of "fitness functions" seems to touch on Genetic Algorithms, and I guess I think less of regression when I hear it.

</comment><comment><USER34> This is a very good explanation! (And a great blog btw). I especially like the math symbols explanation. This is something I always have a hard time understanding/remembering. (It's very hard to lookup math symbols om Google :P) and great that it is followed by a Python example!

</comment><comment> globular-toast The emojis add nothing and make it horrible to read, so I stopped.

</comment><comment><USER35> I consider myself above average intelligence, but my math skills are sorely lacking (didn't make it beyond pre-calculus). The first section was simple to follow but I was completely lost as soon as he hit the "Nitty Gritty."

Any advice on what I need to learn to even begin to understand what's written in section 2?

<comment><USER20> Machine learning math is basically calculus, linear algebra and probability theory. Pick up intro textbooks on these. Enjoying the dopamine rush of insight from blog posts can be more harmful than useful if overdone. You have to sit down and digest these things without diatractions, and that's not easy for most people outside a school environment. Consciously understand this fact and take an adult, planned approach to keep yourself on track if you truly want to understand things.

</comment></comment><comment><USER36> Great read! I really enjoy that the article explains the problem in three different mediums, and you walk away with some understanding even if you can only access the first part. Reminds me of the Wired videos where a concept would be explained at 5 different levels [https://www.youtube.com/watch?v=eRkgK4jfi6M](https://www.youtube.com/watch?v=eRkgK4jfi6M)</comment>


Can i crawl multiple ecomm. website by writing a generalize crawler in Python? - <AUTHOR> I want to get the data from product page of different types of ecommerce website. Is there any tool or tutorial available to write a generalize code for all? <comment><USER2> [http://www.amazon.com/Automate-Boring-Stuff-Python- Programmi...](http://www.amazon.com/Automate-Boring-Stuff-Python- Programming/dp/1593275994?tag=duckduckgo-ffsb-20) . More specifically, chapter 11 - [https://automatetheboringstuff.com/chapter11/](https://automatetheboringstuff.com/chapter11/) .</comment>


Chrome Extension: Visualize browser history as a favicon stack - <AUTHOR> http://golancourses.net/2014/shan/03/06/project-3-shan-browser-history-visualization/

<comment><AUTHOR> Link to the Chrome Extension on Github: [https://github.com/yemount/IconicHistory](https://github.com/yemount/IconicHistory)</comment>


Scientists discover new magnetic element - <AUTHOR> https://phys.org/news/2018-05-scientists-magnetic-element.html <comment><USER2> Clickbait title.

They discovered previously unknown magnetic _properties_ of an _existing_ element. They aren't alchemists.

<comment><USER3> From the title alone I was expecting something with a half-life measured in seconds.</comment></comment>


The blood, sweat, and tears of living the startup life. - <AUTHOR> http://mccannatron.com/2012/03/29/the-blood-sweat-and-tears-of-living-the-startup-life/

<comment><USER2> Really good post. I was talking to a friend of mine last week and he related a great story:

In January of 201X, he was sure his company was going out of business after 6 long hard years.

In May of 201X (same year), XXXXXX (titan we all use all the time) bought his company for $40M.

Hang in there, keep pushing, make progress, stay sane. Get up the next day and do it again.

Welcome to StartupVille.

<comment><AUTHOR> Startups are a marathon not a sprint. It's so hard to appreciate that until you've been in that situation.

</comment></comment><comment><USER3> "If you knew all the hardships ahead beforehand it would be incredibly hard to ever start." \- Even if you thought you knew, many still jump in cause we all think we'd be different. And it's because of that belief that the world is changed!

<comment><USER4> The whole time I read that article I told myself that it will be different for me. The whole time I also knew it won't be different for me. Maybe denial can be a good thing?

<comment><USER5> Even knowing it won't be different, what else are you going to do? Might as well go for it.

</comment></comment></comment><comment><AUTHOR> Author here. I wrote this post in response to a confidential conversation I had with a friend about his company on the verge of going under.

Happy to answer any questions or feedback anyone has.

</comment><comment><USER6> Brilliant! I liked "The experience is the journey itself – It's not about the end (acquisition, IPO, etc) but the everyday moments that make startups what they are." the most... :)

</comment><comment><USER7> very well stated. it's the facebook stories that make headlines and paint a picture that is not even close to a fair representation of reality

</comment><comment><USER8> ...stabbing people with my startup knife.

</comment><comment><USER9> Great post !

</comment><comment><USER10> Great read!</comment>


HTTP 418: I'm a Teapot - <AUTHOR> https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/418 <comment><USER2> Somewhat personally funny story.

Some number of years ago I saw a huge traffic spike on [https://jsonip.com](https://jsonip.com). After investigating, I saw that someone who seemed to have a misconfigured squid proxy that wasn't valid IP data was hitting the api hundreds of times a minute.

The scale of jsonip was a lot smaller back then and still just a personal project but the requests were significantly crushing the server in addition to regular traffic.

As a mild joke, I updated the code to return "418 You are a teapot" for the squid proxy briefly. Just long enough for the user to be "wth" and investigate so they'd update their configuration. I just targeted the obviously malformed requests.

Within a day or so the proxy either stopped making requests or got fixed.

I got a laugh out of it and removed that code. Hopefully the person on the other end also got the joke.

<comment><AUTHOR> That's clever and pretty funny! Thanks for sharing

</comment></comment><comment><USER3> Ah yes, the Hyper Text Coffee Pot Control Protocol.

[https://tools.ietf.org/html/rfc2324](https://tools.ietf.org/html/rfc2324)

Back in the day I really wanted to build an ethernet ready and HTCPCP compliant coffee machine. Never got around to it, but in the days of Pi Zero and similar hardware it's not as of complicated anymore.

</comment><comment><USER4> Honestly, this has been posted about so many times that the only way this shouldn't be flagged as a dupe is if you show us photographs of an actual teapot that implements this response.

<comment><USER5> Not sure if it's actually serving traffic, but here's a teapot someone put a Raspberry Pi in: [http://error418.net/](http://error418.net/)

</comment></comment><comment><USER6> Always thought it cute that the spec mandates 4 allowable alcohol additions... but also completely forgot to specify the list of sweeteners.</comment>


Twitter outage - <AUTHOR> https://api.twitterstat.us/incidents/k9tyyqx4b6mz <comment><AUTHOR> [https://status.twitterstat.us/pages/incident/564314ae3309c22...](https://status.twitterstat.us/pages/incident/564314ae3309c22c3b0002fa/5ada2d8e7afe4904e701f820)

> April 20, 2018 6:14PM UTC [Investigating] Currently people are unable to > Tweet, engineering teams are investigating.

</comment><comment><AUTHOR> The Twitter status page just mentions the streaming API, though I was getting a "Something is technically wrong" error message on twitter.com for about 10 minutes.</comment>