I've always considered NaN too definitive for general industry languages like C, JS or Cobol where not even physics with calculus should be assumed. Maybe its ok for languages that at least expect math for engineers like Fortran or up..
How about we call it "Maybe a Number" and since equality can't work for it we still need a separate way to ask like: Math.whoIsTheMaN(me)
Mere 2 weeks ago, I needed to run 2 PCs with 1 set of mouse+keyboard. I remembered using a great and free little app called Synergy back in the old days, so I ended up in the whole process of (re)discovering Synergy (which now at v3 became a paid app with features I don't need), then its v1 fork Barrier (together with also learning that it is abandoned but nobody had the decency to warn about it in the project page, why people are like that?), and the follow-up Input Leap. What a trip!
All these are addressed in Deskflow README. But I fail to see where it comes from...
is Deskflow a parallel fork that raised simultaneously with Barrier, but now is suddenly gettingmore traction?
How come Synergy itself funds it, which would appear that undermines their commercial offering?
So Deskflow could be called the current-day evolution of the original Synergy v1! Barrier and Input Leap were forks, but this one is the project that acts as upstream to the company that builds a sellable commercial product based on it.
Now that's clearer, after all pieces of the puzzle fell into place.
Yep, can confirm that this is being driven and supported by the Synergy team. I’m a long time subscriber of synergy, having picked up one of their lifetime licenses many years ago.
I stopped using it but recently had the need to revisit it. Encountered a problem with mouse speed between retina (Mac OS X) and a non retina (Windows) display. Was able to fix this using what was the synergy open source base at the time.
I was working on this, just as the transition took place to Deskflow and the team were helpful in getting this fix, over to the new code base.
Very happy with the interaction and open source support.
Ah nice. I used Synergy 1 until Synergy 2, even paid for it. The whole v2 debacle made me stop using Synergy entirely, and I went back to more traditional methods.
Was recently thinking about how I missed the old Synergy. Time to check out Deskflow ig seems.
> He went to the Museum of Natural History to study sharks...
At last, one person who did his homework!
That's what I thought after seeing the first image, the "vagina with teeth" which in my eyes just look like a weird woman's mouth with just some teeth added around... what a terrible work, probably the authour hadn't seen a shark in his life? nor he researched then even a bit, to get some references.
And some exercises can be really intense, too! I have to repeat this over and over to people who complain about not being able or wanting to go to a gym: just start from (carefully) doing some squats or any other youtube-guided exercise in your living room! anything else is just an excuse they're forming in their head to cover for their lack of will to do it.
Try to do Saitama's training (from anime One Punch Man, just a tongue-in-cheek way to mean do lots of push-ups and squats) and afterwards tell me you don't feel like you've done some serious exercise!
Those people were addicts, and not by a bit but deep into it. They should first realize their condition and then apply measures to get out of the hole. I bet they also had very poor sleep quality (regardless of length).
Like crack addicts longing for their dose, I've also seen people not able to work as functional adults until they get their precious morning coffee shot, and when on holidays their company ends up becoming a burden, not able to improvise, not able to stay in uncommon situations without a coffee brewer nearby for a couple days.
I'm a coffee drinker, and I take it around 2 to 3 times a week. To be honest, it takes effort to reach those addiction levels; I don't think it can happen without taking coffee every. single. day., which seems way too much honestly. Like "needing to drink hard alcohol every day seems odd"-levels of wrong.
Coffee addict here. Like any addiction, the ritual is the scaffolding on which the whole thing is built. Sure, I'd get a headache or be groggy without it at first, but having an excuse to sit and sip a warm beverage for 15-30 minutes has become a peace-creating space for myself to think and prepare. When I go on vacation, it's much less important or pressing, because that ritual is broken. There are seldom adverse effects in those situations when avoiding coffee.
There's nothing about this that requires coffee, but habits require primers and repetition, and starting coffee is that primer, and the socially accepted aspect of it maintains those boundaries so it can be repeated. When we go on vacation, it all goes away.
I used to smoke cigarettes as a young kid, and 90% of the reinforcement of that was the ritualistic work smoke break where you sat and bullshitted with coworkers or friends outside for 15 minutes. Without that, the habit broke easily because smoking didn't actually reinforce or be reinforced by anything joyful.
It is easy to look down ones nose at coffee drinking, but the core tie is rarely some crippling physical addiction so much as a ritual that is itself enjoyable, and we all have those. Any guidance on breaking addiction usually centers on the rituals you've created around your substance.
> when on holidays their company ends up becoming a burden, not able to improvise, not able to stay in uncommon situations without a coffee brewer nearby for a couple days.
Exactly. This is why it was so memorable. They made their coffee problem my problem as well. Suddenly the entire morning was a frantic search for coffee. It’s not exactly the vibe I’m going for in the morning.
We're talking in English, not in Go. The meaning doesn't change that much because of using uppercase initials. What you're referring to has already been consolidated as "source available".
No, it's just not speaking idiomatically. The term "open source", with or without caps, has a commonly understood meaning that's widely used. Whatever the individual words mean in the dictionary, together they have a well defined meaning. Applying it to other situations that contradict that meaning just adds confusion.
As an example, you could describe a spinning disk hard drive as "RAM" because it's a memory device you can randomly access. That would meet the dictionary definitions of "random", "access", and "memory". And yet, everyone would be annoyed with you for doing so. "I have 16TB of RAM in my computer!" "No you don't, Kebab. Stop saying that!"
I'm sorry for the snark in my comment, it intended to just be a funny joke due to the capitalization thing (in Go that's what separates public from private fields, which is a weirdness of the language that surprises people the first time they get to learn it)
As others said, while "open" does indeed mean "reachable" or "available" in this context of source code, it happens that "open source" is a well defined thing to allow not only access, but also modification, reuse, and distribution without limitations. So the "open" in "open source" has its meaning brought to the highest level of openness.
> Open source is source code that is made freely available for possible modification and redistribution. Products include permission to use and view the source code,[1] design documents,[2] or content of the product.
> Generally, open source refers to a computer program in which the source code is available to the general public for usage, modification from its original design, and publication of their version (fork) back to the community.
Yeah, it's like if one writes a tiny calculator and names it Disney to learn how to program in Delphi, it's a learning exercise with 0 commercial intent so who cares. But for those who care about the name vanta, get the G from Go and rename it to Ganta, problem solved :-)
with the added benefit that the software family could be extended in the future with other learning exercises such as a Rust forum engine named Ranta
The way I see it, it's 100% crystal clear that YouTube should be asking creators to register the timestamp ranges of their sponsored blocks when uploading a new video, in order to make their Premium subscribers to automatically skip them, as part of the premium they are paying.
Do you mean that creators choose explicitly how many ads to insert and their length? Because if it's just an ON/OFF switch and then Youtube proceeds to put almost equal lengths of ads than of content (1+ min ad after 2 minutes of content, as per the previous comment) then that's truly terrible.
Also... ads after only 2 minutes? Am I the only one who thinks that feels much worse to bear than longer ads more spaced out? There's something that feels odd with having to get interrupted by an ad after mere 100 seconds of watching something.
I think this is the way to bubble up error messages that I like the most. Simple, not needing any additional tools, and very practical (sometimes even better than a stack trace).
The idea is to only add information that the caller isn't already aware of. Error messages shouldn't include the function name or any of its arguments, because the caller will include those in its own wrapping of that error.
If this is done consistently across all layers, and finally logged in the outermost layer, the end result will be nice error messages with all the context needed to understand the exact call chain that failed:
fmt.Printf("ERROR %v\n", err)
Output:
ERROR app.run(): room.start({name: "participant5"}): UseStorage({type: "sqlite"}): Store({userId: "A0101"}): the transaction was interrupted
This message shows at a quick glance which participant, which database selection, and which integer value where used when the call failed. Much more useful than Stack Traces, which don't show argument values.
Of course, longer error messages could be written, but it seems optimal to just convey a minimal expression of what function call and argument was being called when the error happened.
Adding to this, the Go code linter forbids writing error messages that start with Upper Case, precisely because it assumes that all this will be done and error messages are just parts of a longer sentence:
> This message shows at a quick glance which participant, which database selection, and which integer value where used when the call failed.
And it's completely useless for looking up the errors linked to a participant in an aggregator, which is pretty much the first issue the article talks about, unless you add an entire parsing and extraction layer overtop.
> Much more useful than Stack Traces, which don't show argument values.
No idea how universal it is, but there are at least some languages where you can get full stackframes out of the stacktrace.
That's how pytest can show the locals of the leaf function out of the box in case of traceback:
def test_a():
> a(0)
test.py:11:
test.py:2: in a
b(f)
test.py:5: in b
c(f, 5/g)
f = 0, x = 5.0
def c(f, x):
> assert f
E assert 0
test.py:8: AssertionError
and can do so in every function of the trace if requested:
def test_a():
> a(0)
test.py:11:
f = 0
def a(f):
> b(f)
test.py:2:
f = 0, g = 1
def b(f, g=1):
> c(f, 5/g)
test.py:5:
f = 0, x = 5.0
def c(f, x):
> assert f
E assert 0
test.py:8: AssertionError
You have to add all of that detail manually which sucks. You can get the function name from the runtime package and generate that metadata easily with a helper function. Otherwise when you rename the function, you have to rename all of the error messages.
This is covered by the “ergonomics” section of TFA:
> With custom error structs however, it's a lot of writing to create your own error type and thus it becomes more of a burden to encourage your team members to do this.
Because you need a type per layer, and that type needs to implement both error and unwrap.
This is the inverse of the context solution. The point is to provide data at the point of error, not at every call site.
You can always merge these later into a single map and pay the allocation cost there:
var fields map[string]any
for err != nil {
if e, ok := err.(*KV); ok {
for i := 0; i < len(KV.KV); i += 2 {
fields[e.KV[i].(string)] = e.KV[i+1]
}
}
err = errors.Unwrap(err)
}
You can also just assign your errors to variables, and typically you only need to do so for the innermost error. Wrapping calls can just use Errorf with the %w operator.
`err.(type)` is incorrect, at least in general. Calling `errors.Unwrap` in application code like this is almost always a red flag indicating a design error. And in this case it definitely is!
If you're re-implementing errors.As's unwrapping behavior in your application code in order to parse/evaluate errors, that's a mistake and a design error. You'd never call Unwrap outside of a custom error type's method set, and even then you'd never use a `for` loop like you're doing in your example.
> it means you can target types with precision in the API layer
The only situation where you need to get precise error types is when you need to provide specific details from those specific types to the consumer, which is rare. And even in those rare cases, user code does that work via errors.As, not this manual Unwrap loop process you're suggesting here.
> The only situation where you need to get precise error types is when you need to provide specific details from those specific types to the consumer, which is rare.
It's not rare in my experience. All they apps I work on have a central unhandled error handler in the API that converts Go errors to HTTP or gRPC error responses, and then falls back to a general "internal error" if no specific error could be mapped. I can think of many other instances where we have a switch over half a dozen error typed in order to translate them into other types across RPC or pub/sub boundaries.
> And even in those rare cases, user code does that work via errors.As, not this manual Unwrap loop process you're suggesting here.
As() does not work with switch statements unless you pre-declare a ton (in our case, often a couple of dozen) error variables. Secondly, it is deeply inefficient. As() traverses the cause tree recursively for every single error, so if you have 30 possible error types to compare, and an error typically wraps 3 layers deep, that's a worst case of 30 loop iterations with 90 cases, as opposed to my method, which is 3 loops.
> t is deeply inefficient. As() traverses the cause tree recursively for every single error, so if you have 30 possible error types to compare, and an error typically wraps 3 layers deep, that's a worst case of 30 loop iterations with 90 cases ...
I have no idea how you came to this conclusion. It's certainly not what happens when you call errors.As in your application code.
There's no situation where your application code would ever have 30 error types to compare against, if that were ever the case you have seriously fucked up!
var a, b, c error1, error2, error3
switch {
case errors.As(&a):
...
case errors.As(&b):
...
case errors.As(&c):
...
}
…then yes, you will be doing 3 searches, each of which will do a loop (sometimes recursively if Unwrap() returns []error) over the chain of causes.
> There's no situation where your application code would ever have 30 error types to compare against, if that were ever the case you have seriously fucked up!
That is your opinion. In my experience, that is not the case, because there are lots of cases where you want to centrally translate a canonical set of errors into another canonical set.
> It literally is not. Is and As are not merely convenience functions, they're canonical …
This is just your opinion. If you actually read the documentation, you will see that it merely says Is() and As() are "preferable" to checking.
Any code that looks like that is almost certainly broken. If the things you're describing as "my opinion" are counter-indicated in the code that you're used to working with, then you're working with code that's seriously unconventional. Do with that feedback what you will.
You're wrong. You've not offered any evidence for why this is not just your opinion, and your claims are easily contradicted by examples.
As an example, say we have an API implemented on top of a complex data store. Every data store implementation can return errors like ObjectNotFound, InsufficientPermissions, and a dozen others. Every data store call can potentially return these. As well as, of course, standard Go errors like DeadlineExceeded or internal errors that cannot be exposed as user-facing API responses. However, some translation error has to translate those errors into API responses.
This cannot conveniently and consistently be done in each API handler, as it would repeat the same error translation for the same errors. An InsufficientPermissions error may happen in a "create" route as well as an in a "update" route, but also in any other route that deals with objects not being accessible.
Therefore it must be done in a central error translator. By definition. And this translation must either do a dozen+ Is() and As() calls, or it can be done efficiently, as I've described.
Anyway, I've said all I have needed to say and won't respond any further.
> it must be done in a central error translator. By definition. And this translation must either do a dozen+ Is() and As() calls, or it can be done efficiently, as I've described.
These claims are, bluntly, incorrect. There are no widely-used modules that work this way, and there are no properties of the language or its conventions that would suggest that this is a viable way to design an API. errors.Is and errors.As provide capabilities that type assertions -- as you've described -- factually do not provide. They're not equivalent, they're not normally used, they're not anything other than red flags in bad code that should be eliminated.
I'm not trying to pick a fight with you, I'm honestly just trying to prevent other people, reading this comment thread, from making the kinds of design mistakes that you're describing here as viable and efficient. They truly aren't.
That is just your opinion. There is absolutely nothing wrong with doing so, and there is nothing in the documentation that asserts what you claim.
The documentation is clear that comparing an error value or casting it without following the Unwrap() chain is only an antipattern because it would not work with wrapped errors.
Is() and As() are merely convenience functions, and the documentation is clear that all they're doing is calling Unwrap(), which you can do yourself.
It literally is not. Is and As are not merely convenience functions, they're canonical and conventional expectations of Go code, if you're doing that work yourself you're almost certainly doing it wrong.
reply