Hacker Newsnew | past | comments | ask | show | jobs | submit | more lubutu's commentslogin

I'm very fond of typography, but I don't know all that much about it. Is there a name for the style of fonts like Elena? As soon as I saw the sample I was struck by the similarities to Minion, which has to be my favourite serif font (though I do prefer some aspects of Elena).


Not an expert in typography so I may be wrong, but I'd say it's a modern take on Humanist (also known as Venetian), one of the earliest Roman typeface styles. Here's a good article about this style: http://ilovetypography.com/2007/11/06/type-terminology-human.... I'm not sure if it can be classified as such though because it is built to work well on the screen and so has a lot of straight lines, closer to Transitional typefaces like Times New Roman, but even though the overall design is very modern, the feel of it seems to me closer to the Humanist typefaces. For example, the bar on the 'e' is sloping a tiny bit upwards, which is a distinctive characteristic of Humanist typefaces.


Notice 'parseLogLoudly'. You could not implement that using your set of functions: you are not allowing for other code besides 'resume' inside the 'handle' blocks.

Also, I don't believe the mass duplication of code necessary for your approach is acceptable, even within a library.


>Notice 'parseLogLoudly'. You could not implement that

Fair point, and that's due to my failure in not providing an optional side-effect function arg to `parse-log-skip`. And this brings up a related point, namely that the author of the lib is still responsible for crafting the API. For example, if the author of `parseLog` had not included `recover FixEntry`, would it be possible for the caller to implement it via a condition system? Would that even be a good idea? Using the pseudo-python, the only approach I can think of would be:

    def parseLogInteractively(file):
      do:
        return parseLog(file)
      handle ParseError, e:
        line = askToFixEntry(e.text)
        retry
That reference to `line` is pretty horrific.

Perhaps this is one of those cases where a simplified example helps convey the concept, but is too simple to show where other approaches would fall short.

>mass duplication of code

I'm not clear on what you mean. Multiple functions with different behaviour seems not to altogether different from one function with implicit switches that change its behaviour.


Suppose we were attempting to write parseLogInteractively by just returning errors (as in idiomatic Go).

If parseLog just returned an error upon failure we would have to same problem as exceptions do, as explained in section 1. So we have to make parseLog return two lists: one of entries, and one of errors. We would then have to search through the error list fixing and reparsing each error. In Python this would be something like,

  def parseLogInteractively(file):
      return parseLinesInteractively(file.readLines())

  def parseLinesInteractively(lines):
      entries, errors = parseLines(lines)
      if errors:
          entries += parseLinesInteractively(askToFixEntry(e.text) for e in errors)
      return entries
Again we lose the ability to abstract the function 'parseLog'. And I don't know about you, but this looks far worse to me than "resume FixEntry" in terms of exposing implementation details.


In python, I usually deal with this with generators. It's not as elegant as conditions, but it works well enough. I've never tried to permit custom restart-like behavior, but now that generators are coroutines, it should be doable.

e.g.

    def parseEntry(line):
        try:
            parsed = foo(line)
            yield parsed
        except SomethingBad:
            yield None
Common lisp could really use some better coroutine support (and some way to specify generic sequences). Sure, you can do it with macros, but it gets horrible fast. Have you looked at SERIES, for example?


> I've never tried to permit custom restart-like behavior, but now that generators are coroutines, it should be doable.

It would be extremely awkward, you'd need a big dispatch table handling the generator's result and send()ing restarts up to the generator, and of course you lose condition's ability to work through stacks of blissfully unaware code, and to have default behaviors (in Smalltalk, the default behavior — in an interactive image — is to pop up a dialog asking the user if he wants to unwind the stack [as in an exception], to open a debugger at condition point or to try resuming the condition [under the assumption that the user fixed some incorrect method, or checked his network access])


Thanks for the pointer; I've been learning some Smalltalk lately, but I haven't yet looked into the condition system.

And, yes, I'm not saying that manually implementing pseudo-restarts is something I'd ever want to do, but some vague skeleton of the possibility is there.


If you want the restart, you need to take advantage of the PEP-342 two-way yield(), as in:

    ...
    except SomethingBad:
        yield None 
        restartRequest = yield None
        if restartRequest:
            do whatever is necessary to go on
The problem with the above is that the double yield() ugly. You cannot do this with single yield() because the caller would have to know in advance that next() will return None.


Maybe something like: https://gist.github.com/3598432

although perhaps passing a 'handlers' object down, with which handler functions could be registered might be better?


Generic sequences are coming to common lisp. I'm working on a simple implementation inspired by clojure which I'll be posting to /r/lisp in the coming week.


Do not separate errors and entries. Instead use something like Haskell's Maybe, but instead of an empty Nothing-object you return something which contains error information:

  def parseLogInteractively(file):
    entries = list()
    for line in file:
      entry = parseEntry(line)
      if entry.failed:
        entry = askToFixEntry(entry)
      entries.append(entry)
    return entries
A design question arises: Do you need to fix parse errors before you can proceed with next entry? If not, the error handling can be done by whomever calls parseLog.


The abstraction problem remains: you are reimplementing parseLog every time you write a new handler, as I described in section 1.

(By the way, you're looking for Haskell's Either type, but ([a],[b]) and [Either a b] are equivalent here.)


No, you only implement this one:

  def parseLog(file):
    list = []
    for line in file:
      list.append(parseEntry(line))
    return list
Or better (more pythonic imho):

  def parseLog(file):
    for line in file:
      yield parseEntry(line)
The second version is lazy (if file reading is lazy), so you can even abort parsing or fix the state on an error. Here are your different versions all reusing parseLog from above and equivalent line count to condition handling:

  def parseLogLoudly(file):
    for entry in parseLog(file):
      if entry.failed:
        print "Warning:", entry.message
      else
        yield entry

  def parseLogSilently(file):
    for entry in parseLog(file):
      if not entry.failed:
        yield entry

  def parseLogInteractively(file):
    for entry in parseLog(file):
      if entry.failed:
        yield askToFixEntry(entry)
      else
        yield entry
(Haskell's Either has "Left a" or "Right b". I want something like "Just value" or "Error msg", but you are right Either is nearer than Maybe)


Haskell's Either type is conventionally used exactly like that--pretend that Right val is Just val and Left err is Error err.

The reason it doesn't have those names is because it is more general; you can also use Either to model things like early termination. The generic names just make it clearer that it isn't exclusively for error handling unlike exceptions. In other languages using exceptions for more generic control flow is considered poor style, but in Haskell using Either for non-error cases is completely reasonable.


(It's conventional to use Left for errors and Right for successes.)


Sounds like this is just an opaque way of providing a strategy or callback to the parseLog method. Why not something along the lines of (scala):

  def parseLogInteractively(file) = parseLines(file.readLines(), error => askToFixEntry(e.txt))

  def parseLines(lines, errorHandler) = lines flatMap {
    tryParseLine(_) fold {success(l) => Some(l)} {error => errorHandler(error)}
  }


> Why not something along the lines of (scala):

Because that only works for very flat stacks, otherwise your callback will start infecting more and more method less and less related to what's actually causing the error, and then you'll have to move to a mapping of callbacks as different parts of the stack will want their own error callback.


Do you really want to handle error conditions in a resumey way far further up the stack? I'd expect most cases are either handle the error close to the cause, or a single application-wide handler (which could be provided with dependency injection).

The condition handling approach just seems too magic to me. It seems to mean the "inner" code calls another method defined somewhere else - but that "somewhere else" is defined by the call stack, something that's not really very visible in the code.


> Do you really want to handle error conditions in a resumey way far further up the stack?

"Way far" is relative and depends on a number of factor. And I don't consider half a dozen stack frames "way far", it's very easy to attain when using a coding style emphasizing small short methods which call one another.

You also have no bloody idea how the library works internally.

> I'd expect most cases are either handle the error close to the cause

Again, "close" and "far" is relative. I want to handle the error at the closest point to its triggering, but I'm also limited by the data available to know how to handle it. One pushes the handler down the stack, the other up.

> The condition handling approach just seems too magic to me.

There's nothing magic to it.

> It seems to mean the "inner" code calls another method defined somewhere else - but that "somewhere else" is defined by the call stack

Welcome to dynamic scoping, there are cases where it's useful.

> something that's not really very visible in the code.

How is "I'm signaling a condition" not very visible in the code? It says right there that it signals a condition.


"The condition handling approach just seems too magic to me."

They're nothing compared to Lisp's macro facility.


I'm not exactly a fan of that either


I've wondered about the "two week problem" in the context of large open source projects. It would be great if a developer could spin up, say, a temporary VPS for Chromium development, the toolchain all set up and source ready to modify. I can't be the only one with a pet bug that must be trivial to fix, but the overhead of setting up a whole new toolchain to do so is just not worth it.


I was able to get Chromium compiling on my laptop (2010 MacBook Air) in a few hours using one of the tutorials on their Wiki. Most of my time was spent waiting for things to download and compile. Why would you need a VPS setup? If you want to do it in the cloud, isn't AWS enough?


It amazes me that the argument against this is by attacking some "standard-bearer of his cause." Let's not ask how it is compared to existing alternatives, or to 'perfection', but rather the potential alternatives. Your argument is akin to "stop talking about 'engines'; horse-drawn carriages might suck, but so does walking."


He's not talking about engines though, but at about some golden age in Unix's history when All was Right. Or at least that's part of what I got from it.

He also mentions 'one person having responsibility'. Does he mean a benevolent dictator? Linux and Python have that. They're imperfect in their own ways too.


Likewise the emphasis! Although you're right that a lot of languages are bureaucratic with enigmatic exceptions and so on, I think that a well-typed language is better to learn to begin with than one which basically accepts whatever nonsense you throw at it. I'm not sure the perfect beginner's language exists, but I personally believe that if it did it would be statically typed.


I've noticed that the NUL-termination problem [1] has come up a number of times in these comments. If you want a solution to this that isn't so drastic as an object system, perhaps take a look at Usul [2], non-POSIX 'tabular' Unix utilities which use an AWK-style $RS.

[1]: http://news.ycombinator.com/item?id=4369699

[2]: http://lubutu.com/soso/usul


As Rob mentions in his post, the more dotfiles there are in $HOME the slower path resolution for any subfiles becomes. How do we navigate to ./src? We open the directory and read all the entries until we find the one called "src". What happens if we encounter a morass of dotfiles beforehand? src takes a while to find. The clutter may be invisible to you, but it does gum up the works.


For what it's worth, most modern file systems (JFS, XFS, ext4, reiserfs, btrfs, ...) have logarithmic (or better) directory lookup times. This is achieved using hashes and b-trees (or even hash tables).


Fair point. Though anything using the standard POSIX dirent API would still get the performance hit (even if path resolution doesn't).


Unless you have many thousands of files, I can't imagine you would ever notice a slowdown.


A meta-corollary: whenever a headline with a question mark appears on Hacker News, there will be at least one comment referring to Betteridge.

(Please, can this stop?)


Ultra-meta: Whenever a repeating meme occurs on the internet, there will be someone asking for it to stop. And the answer to whether it will stop will be no.


Recursive-super-ultra-meta-induction: Whenever someone refers to a level of meta-ness, someone else will refer to level n+1.


Transparently false: this thread's length is measurably finite.


For now.


It will always stop, at least for the most part. It will take a long time, though, and by then it will only be a dim memory, so you probably won't notice.

(Netcraft confirms: BSD is dying!)


Why? I never heard about this "law", and now I just learnt about it.


Analogously, "you don't need maths to tell you that one and one is two."


As soon as you have an understanding that one and one is two, you have maths.


Consider applying for YC's Winter 2026 batch! Applications are open till Nov 10

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: