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

Really like your UI! Built something similar for myself (also as an replacement for hckrnews.com): https://hnhub.dev/


Great work with this, I like that we both thought to tackle similar things like sorting by date/score/comments within the timeline itself.


Totally agree with you. I don’t really need more features (maybe +2 page rules?) but having a way to give back without paying per site would be awesome.


Can recommend kopia as well. It is the one that I settled with after trying out pretty much all the other open source solutions (at the time).

Works great across all my devices (win, mac, linux).


I found the official API quite a pain to work with while building myself an alternative "hn ui"[0]. I mostly switched over to using the Algolia API[1], which is a lot more "fun" to work with. I can only recommend checking that one out as well.

[0]: https://hnhub.dev/

[1]: https://hn.algolia.com/api/


From Rob Pike on reddit regarding this post[0]:

The and and or functions in the template packages do short-circuit, so he's got one thing already. It was a relatively recent change, but it's there.

Non-deterministic select is a critical detail of its design. If you depend on a deterministic order of completion of tasks, you're going to have problems. Now there are cases where determinism might be what you want, but they are peculiar. And given Go's general approach to doing things only one way, you get non-determinism.

A shorthand syntax for trial communication existed. We took it out long ago. Again, you only need one way to do things, and again, it's a rare thing to need. Not worth special syntax.

Some of the other things mentioned may be worth thinking about, and some of them have already (a logging interface for instance), and some we just got wrong (range). But overall this seems like a list of things driven by a particular way of working that is not universal and discounts the cost of creating consensus around the right solutions to some of these problems.

Which is not to discount the author's concerns. This is a thoughtful post.

0: https://old.reddit.com/r/golang/comments/s58ico/what_id_like...


> Again, you only need one way to do things, and again, it's a rare thing to need. Not worth special syntax.

This really is one of the parts I like the most about Go. It really makes so many things simpler. Discussing code, tutorials and writing it.

Every time I'm trying to do something in JS I have to figure out why every guide has a different way of achieving the same thing and what are the implementation differences.


It'd be nice if he had at least hinted towards what 'the way' is for this problem.


It’s in the article he’s responding to.


> but (deterministic-select cases) hey are peculiar.

It looks for most select blocks in Go code, it doesn't matter whether or not they are non-deterministic or deterministic.

But, if the default is deterministic, user code could simulate non-deterministic, without much performance loss. Not vice versa (the current design).


Er, when it comes to concurrency, non-determinism is usually cheaper than determinism. As soon as you care about ordering, you almost always have to synchronize, and that has a cost.

Austin Clements (of the Go runtime team) wrote a paper that explores this in detail [1]. That was before joining the Go team, but the concepts are universal.

[1] https://people.csail.mit.edu/nickolai/papers/clements-sc.pdf


> Not vice versa (the current design).

    select {
       case: <-chan1_whichIWantToCheckFirst
       default:
    }

    select {
       case: <-chan2_whichItreatTheSameAsChan3
       case: 0xFF ->chan3_whichItreatTheSameAsChan2
    }


Yes, as I have mentioned, there is performance loss, comparing to

    select {
       case: <-chan2_whichItreatTheSameAsChan3 // a higher priority
       case: 0xFF ->chan3_whichItreatTheSameAsChan2
    }


The real usecases where I need deterministic select, are so few that a small performance loss doesn't matter to me.


Sometimes, it is not related to performance loss, it is related to implementation cleanness and complexity.


A separate `select` with empty `default` is about as simple and clean as it gets. It is easy to read, easy to reason about, and, most importantly, conveys the intention of the code perfectly.


1) Is there really a performance loss compared to if select was deterministic?

2) What in the world do you need such code for?


1) surely.

2) just read:

     https://groups.google.com/g/golang-nuts/c/SXsgdpRK-mE/m/CT7UjJ3aBAAJ

     https://groups.google.com/g/golang-nuts/c/ZrVIhHCrR9o

     https://groups.google.com/g/golang-nuts/c/lEKehHH7kZY/m/SRmCtXDZAAAJ


> user code could simulate non-deterministic

I'm curious how?

> Not vice versa

There are pretty common patterns for this. At least for real word cases where you might have one special channel that you always want to check. Ugly, but in relation to the previous question, I don't see how one is doable and one isn't?


> > user code could simulate non-deterministic

> I'm curious how?

    if rand.Intn(2) == 0 {
        select {
           case: <-chan2_whichItreatTheSameAsChan3 // a higher priority
           case: 0xFF ->chan3_whichItreatTheSameAsChan2
        }
    } else {
        select {
           case: 0xFF ->chan3_whichItreatTheSameAsChan2 // a higher priority
           case: <-chan2_whichItreatTheSameAsChan3
        }
    }
Yes, it increases verbosity to the other way, but no performance loss.


How in the world is generating a random number and branching and doubling the number of instructions "no performance loss"?


Now the non-deterministic implementation does more work than a deterministic implementation. It generates a random number and sorts the branches. The latter (sorts the branches) is not needed in the above pseudo code.

Doubling the number of instructions has no impact on run-time performance.

And there are more optimization opportunities in implementing a deterministic design. Now, the non-deterministic implementation needs to lock all involved channels before subsequent handling, a deterministic implementation might not need to.


Any time there is more than one channel being selected for it needs to cover them all equally.


Equality is meaningful only if at least two case operations are always non-blocking. This is rare in practice.

In fact, in practice, sometimes, I do hope one specified case has a higher priority than others if they are all non-blocking.


As far as priority goes, most interesting cases will have priority based on the data in the read, except for this specific case of a done chan el and a data channel. I used that pattern at first but have been moving away from it. To be sure i am mostly writing long lived processes with fixed pools of worker go routines and either never exit or exit based on WaitGroups determining the work is all done.


Yes, it (the lack of deterministic-select) is only annoying for several special cases. For most cases, it doesn't matter whether or not the default behavior is deterministic.


Wouldn't it be the case id one worker was pulling work asynchronously delivered from two places? I only use one go routine / one channel myself, but the name select itself very strongly implies it is a yield type operation where any of a number of async actions can wake it for their callback to run. Albeit without a callback syntax, it is async and better be fair.


I agree. I really like how the `time` crate[0] in the rust world handles this[1].

with your example:

> format_description!("[year]/[month]/[day]")

0: https://crates.io/crates/time

1: https://time-rs.github.io/book/api/format-description.html


This is easier to read but not descriptive enough since there are different kinds year, month, day. Year can be 2 digits, 4 digits, regular or week year. Month can have leading zero or not, long name, short, name. Day could be Julian, leading zero or not, day of the week, etc


That's when you can be more precise if you want: `[year padding:zero repr:full base:calendar sign:automatic]`. The format is also checked on compile time.


How long until that becomes Turing-complete ;)


+1 for strongly typed and compile-time checked, but I'm still not a fan of a sub-language within a string literal. The language already has syntax to structure things, why make a separate language within strings?


In the context of the original article addressing Java 8, in the java.time.format package, there's a DateTimeFormatterBuilder that removes the sub-language element of the issue. With those builder methods, you can construct the fields in the order you want, with whatever precision, with padding, etc.


> The language already has syntax to structure things

I don’t think the language has anything suitable for these purposes. What did you have in mind?


I don't know about Rust. Several people responded that Java already has a builder interface for creating a format string. That is possibly more type erased than the Rust macro equivalent. In C++ I would use variadic templates, as I originally proposed in my root comment: `format(year(), '/', ...)`.


The format_description! macro uses the same syntax as the format_description::parse method. If you want to support user-provided formatting strings (which you do), then you need such a method already, and once you’ve got that, why do the macro differently?

That components have parameters makes the non-literal approach even less compelling: take this which can produce the likes of “2:34:56pm”:

  format_description!("[hour padding:none repr:12]:[minute]:[second][period case:lower]")
For reference, that is equivalent to this:

  use time::format_description::{FormatItem, component::Component, modifier::{Hour, Minute, Second, Period, Padding}};

  [
      FormatItem::Component(Component::Hour(Hour { padding: Padding::None, is_12_hour_clock: false })),
      FormatItem::Literal(b":"),
      FormatItem::Component(Component::Minute(Minute { padding: Padding::Zero })),
      FormatItem::Literal(b":"),
      FormatItem::Component(Component::Second(Second { padding: Padding::Zero })),
      FormatItem::Component(Component::Period(Period { is_uppercase: false, case_sensitive: true })),
  ]
You could easily provide a prettier DSL so that you could write something like this:

  use time::format_description::shorthand::{HOUR, MINUTE, SECOND, PERIOD, literal};
  [
      HOUR.padding_none().repr_12(),
      literal(":"),
      MINUTE,
      ":".into(),  // even this if you wanted
      SECOND,
      PERIOD.case_lower(),
  ]
This wouldn’t be awful in the absence of the parse method, but really, once you have that, the format_description macro is just what you want: compact, checked at compile time, and matching a runtime equivalent which can take user-provided format strings.

(Now there are two or three changes I’d prefer to make to format_description’s syntax: I’d use = instead of :, the two being generally very similar but : far more regularly occurring in literal parts, so that the different = would make it scan better; and I think that escaping opening square brackets by doubling them but not requiring doubling for closing square brackets was a particularly bad idea; and I’m mildly inclined to prefer {} to []. So I might end up with "{hour padding=none repr=12}:{minute}:{second}{period case=lower}".)


I'm getting the following on visiting the page, couldn't have said it better:

> Unexpected Server Error

> Cannot destructure property 'series' of 'e' as it is undefined.


welcome to javascript


Hey, OP here. The site was down because it exceeded the API calls limit of the headless CMS I'm using.

I forgot to add some basic caching to the site, and it absolutely backfired when the "HN effect" happened on a Saturday while I was on a fishing trip. Perks of the modern like.

It's back up now, hope you enjoy the reading!


looks like it is custom built: https://github.com/shaunlebron/t3tr0s-slides


project: postcard.zone (https://postcard.zone), its a simple way to send a postcard to any address of your liking with fully customizable front and back of the postcard itself.

A long time on my todo list to make more out of it. It works as-is but I'm not happy with the current editor and some other things. Still, it gets some use on occasion which is nice :)


The library calls back home to validate the key (URL: https://errorship.com/api/?errorshipLicensekey={errorship_li...). If it fails it raises an Exception. I don't think that this is the correct way to do this.

If your server is down, my application would crash too. Just cut the license validation out of the library. If I wanted to use the library without an license I could do so anyway.

edit: as noted by the author below, this is not the case :). If the server is not available, it won't raise an exception. I did miss that part somehow.


> If it fails it raises an Exception... If your server is down, my application would crash too

So first off, let me just say that I completely agree. If this were the case, that'd be fucking atrocious and would definitely be a blocker for using it.

But I'm curious how you came to that conclusion.

It took me < 2 minutes of looking at the source code[0] to determine that your claim was incorrect. Not only does it appear to gracefully handle the server being unavailable, the developer literally commented that code explaining that they wanted to ensure users could continue uninterrupted if the errorship server is unavailable.

> We give people the benefit of doubt.

> We only consider people to be not authorized if the backend comes back with an authoritative answer to that effect.

> Else, any errors or any other outcome; we assume authorization is there and also assume they belong to the highest pricing plan: Enterprise

> # failure of errorship should not lead to people been unable to ship exceptions

And it took even less time than that to run a new Python Docker container, install the library, run the sample code, and validate my assumptions[1] (the first attempt fails because the key is invalid, I disabled Internet access for the second attempt and it succeeded).

So I'm legitimately curious - did I miss something? Is there another failure case I didn't catch or test for? Or did you just make an assumption and not bother to verify it? And if it's the latter, why? What was the point? Like, to be frank, if this was a news piece I could understand the (possibly inaccurate) commentary. But why take the time and energy to write your comment and tear down someone's personal project with seemingly inaccurate claims?

(To be clear, no affiliation with errorship, I'm not even a DataDog user. Just a random dev browsing HN).

[0] https://gitlab.com/errorship/errorship_python/-/blob/master/...

[1] https://gist.github.com/citruspi/16d359ac2dafef6fc876e2dd101...


Hi.

> If your server is down, my application would crash too.

The errorship library is written in such a way that it fails open. If our servers are down(or any other failure), it does not affect your application and your application continues to work okay.


Hey, I edited my comment. I did miss the part in http.py somehow :). Thank you for clarifying.


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

Search: