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

If 41% of households are actively employing a cleaner then it seems very likely that more than 50% would be happy to have their home cleaned if only they could afford it (as opposed to the commenter starting this thread, who seems to see household cleaning as a positive part of their life).

How big of a bubble do you have to be in to be thinking "I like cleaning" is the majority position among normal people?

Is it “I like cleaning”,

or “I benefit from knowing some moron didn’t come flood the cracks of my floors and wood cabinetry, creating mold”?

Yet to come across pros doing it better than me, means I don’t hire pros yet.


Traditional automated refactoring tools cannot read multiple functions and, in one go, determine what subsets of all of those functions relate philosphically to the SQL queries (not just the actual queries themselves) and pull those out into a new coherent interface in a new file.

That sounds fantastic but it's essentially a different subject.

You seem to be dismissing any music that you don't have some pretty close participation in. Did it all start to go downhill with the invention of the gramaphone? Listening to Ella Fitzgerald or Vera Lynn or Elvis or Frank Sinatra was irrelevant for those that weren't actively jamming along with them?

I'm being facetious, I know you don't really mean that. My point is, listening (on your own, with no musical skill) to good quality music made by a real human is a valid activity. That's under threat, and the fact that making your own music with your friends isn't (or at least is less so) shouldn't detract from that.


> If you see a[i][j] it could mean two completely different things:

> 1) ... a[i][j] == *((char*)a + i*M + j) // I added the char* cast to make it correct

> 2) ... a[i][j] == *(*(a + i) + j)

You may already understand this but: even in case (1), you still have

   a[i][j] = *(*(a + i) + j)
(It has to - that's what operator[] means in C.)

It's just that, in this case, `a + i` is applying pointer arithmetic to char[M]* so it adds M * i bytes to a's address.

This is similar to how `a + i`, if a is int32_t*, will give you an address 4 * i bytes bigger than a.

Really the confusing part of this is that *(a + i), which is an array value i.e. has type char[M], decays to char* when you add an integer to it (or dereference it). This is a pretty crazy hack really. Imagine if, in C++, you could do this

   std::vector<int> v = {1, 2, 3};
   int* x = v + 1;   // equivalent to &v[1]
Yuck.

Too late to edit but I wrote pointer to char[M] as char[M]* when, of course(!), it should be written as char(*)[M].

Probably reasonable, but that means you're disagreeing with the article's point about goroutines being good for LLMs (since goroutines are a form of concurrency). I've never seriously used Go so I don't know how easy it is to avoid using them.

> Python is the same story but sung in a different key. Asking a simple question like “which package manager are you using?”

This is annoying but only needs to be solved once at the start, either by the LLM or the human guiding it. A single prompt of "Set up a uv project in this directory with Python 3.13" is enough that it's never an issue again for that repo.

> Goroutines are a far more tractable primitive for coding agents than threads, callbacks, async/await, or any of the colored-function regimes that dominate elsewhere.

I disagree with this. Goroutines, along with threads, callbacks, and traditional async, are all in the same category: spaghetti of unbounded background tasks. Structured concurrency [1] on the other hand is dramatically easier to reason about. Python has support for this (in Trio and asyncio.TaskGroup) as do other languages like Kotlin and Swift. Function colouring a red herring; if anything, it's useful because it highlights the scheduling/cancellation points in your code.

[1] https://vorpus.org/blog/notes-on-structured-concurrency-or-g...

-----

This really does read as "Go is my favourite language". In fairness, that's a good reason to choose a language to use with an LLM (so long as it's powerful enough and not too obscure). But let's not pretend it's the best language for everyone.


> This really does read as "Go is my favourite language".

Because it always is that.

People advocating for boring languages always advocate for their boring language. For instance, if you tell a gopher that you agree with the point, and therefore the project is going to use java, they won’t be happy about it.


Except for the part where he says that he found Go infuriating to use as a developer prior to LLMs.

RE the article you've linked:

> everyone knows goto was bad.

Absolutely hard disagree. You can write extremely clean and resilient C with C89, goto, and a handful of rules. Telling people `goto` is bad is how we get shitty C programs and paradigms where goto would have been better.

Goto isn't bad, its misuse is bad. Beginners will write shit code regardless of whether you tell them they can or can't use goto. That's also exactly what Dijkstra was arguing, if you read past the much misquoted "goto considered harmful", which he never said (it was an editorialized title, and not even the full version).


> > everyone knows goto was bad.

> Absolutely hard disagree. You can write extremely clean and resilient C with C89, goto, and a handful of rules.

That's a different goto. The one in C89 can only jump around within functions, but the article is talking about goto that can jump between any two points in the whole codebase arbitrarily. It stresses that point a bit more later on in the article, but you can already see it from the FLOW-MATIC code quoted above (which doesn't even have functions).

Your point actually still stands: it's theoretically possible to write clean code using even the more general goto. (Probably by building abstractions with it like "function" and "for loop".) But would you be happy doing that with someone else - or especially with a coding agent? It's better that the "handful of rules" are enforced by the language, in my opinion.

---

Edit:

> That's also exactly what Dijkstra was arguing, if you read past the much misquoted "goto considered harmful", which he never said

I just re-read the original "GOTO considered harmful" article (it's short and clear) and, while the title might not have been his, Dijkstra was definitely making a very plain argument that goto is bad for everyone and should be scrapped. He says in the introduction:

> I [have] become convinced that the go to statement should be abolished from all "higher level" programming languages (i.e. everything except, perhaps, plain machine code).

And in the conclusion:

> The go to statement as it stands is just too primitive; it is too much an invitation to make a mess of one's program.


Here is a structured cross-codebase GOTO for C++, with optional declared & typed continuation values, sub-tasks/states/state-machines, and optional delegated typed termination values.

  // Syntax: { ...; y = go_to state1(x, ...); }
  // Meaning: Cross-codebase GOTO w/continuation values
  // Implementation: tail call
  #DEFINE go_to return

  // Syntax: { ... y = go_do state2(x, ...); ... }
  // Meaning: Cross-codebase sub-task/sub-state
  // Implementation: normal call
  #DEFINE go_do

  // Syntax: { ... go_terminate(y); }
  // Meaning: State machine termination
  // Implementation: normal return
  #DEFINE go_terminate return

  // Syntax: int state3 state(int x, ...) { ... }
  // Meaning: Structured state definition
  // Implementation: normal function
  #DEFINE state

  // SYNTAX: if (GOTO_NOT_HARMFUL) { ... };
  // Meaning: GOTO is now cleaned up
  // Derivation: Achieved
  #DEFINE GOTO_NOT_HARMFUL true
Example:

  int state1      state() { ...; go_to state2(m); }
  int state2 state(int m) { ...; y = go_do substate2a(); go_to state3(); }
  int substate2a  state() { ... ; go_to substate2b(q); }
  int substate2b  state() { ... ; go_terminate(q); }
  int state3      state() { ...; switch (...) { case 1: go_to state4(v); case 2: go_to state5(); ...} }
  int state4 state(int v) { ...; go_terminate(r); }
  int state5      state() { ...; go_to state3(); } // State cycle
So now you can have your #include <go_to>

EDIT: Compressed/cleaned up my mess


That's not the same: you have to cooperate in the game, so if you have a library that uses it internally and you call one of its functions in the normal way then it will still just return as usual. So it still provides the usual guarantees of function calling, even if you don't want it to.

(It also doesn't allow you to jump into the middle of a function, or to take more than a finite number of steps unless you're using a compiler with guaranteed tail call elimination.)


Just to add:

If you want to have proper jump-anywhere goto in C, you can do it a lot more simply than that: just put all your code in one function and use regular goto. If you want to use only structured programming constructions, use a while(true) loop with a switch statement inside.

The fact remains that code outside that function can still call it safely in the normal way.


I have written C code for several decades. I hate a priori, divorced from context, rules such as "never use goto". "Avoid premature optimization" as a rule is much worse. I used goto a few times in that timespan, surrounded it with rebellious comments, but largely the advice has more than weakly held for me. I don't think goto somehow liberates C developers and avails superior architectures.

Bad code is result of not following enough good practices rather than following one too many. Goto creates too much cognitive load. It had to be phased out to make room for better ideas on describing the intention with code more clearly.

> Function colouring a red herring

Any time you see anyone overly fixating on "function coloring" for any context other than ancient versions of Javascript it's a clue that the speaker has no idea what they're talking about.


> Goroutines are a far more tractable primitive for coding agents than threads

Goroutines are literally threads. Yeah, this really is a "go is my fav" article.


I use both go and python in my day job. The code that Sonnet produces for Go is much better than the Python it creates.

This could be because our go code is typically smaller more defined services but I don't really believe that since even the isolated python services are pretty spaghetti looking.


Goroutines are not directly equivalent to threads.

If 100 goroutines are handled by 10 threads, the effect on correctness is identical: any two can be running in parallel with each other (not just concurrently). From the point of view of this discussion, that's all that matters.

Correctness is nice but performance characteristics exist too.

They used to not be, because they were cooperatively scheduled and threads can be preempted. But they added goroutine preemption in Go 1.14 so in practice there aren't really any significant differences to threads, at least in semantics. (At least as far as I remember; been a while since I wrote any Go.)

You can be pedantic and say they aren't technically threads but that doesn't really matter from a programming perspective.


Even when goroutines were cooperatively scheduled, because the cooperation was mostly hidden and every function call was a yield point the average developer would treat them as being cooperative... until they spawned too many goroutines with a tight loop (and no function call) and the runtime locked up.

> You can be pedantic and say they aren't technically threads but that doesn't really matter from a programming perspective.

They are technically threads: they are independently scheduled, concurrent units of execution sharing an address space. They're just not OS (or kernel) threads. Hell, technically userspace threads (generally cooperatively scheduled) are the original, they predate kernel threads by a decade or two.


As someone below said, they might be from programming perspective, but technically they are not. See GOMAXPROCS for more info.

That being said the whole `tractable primitive` thing used in the article sounds somewhat sloppy to me. I don't quite get it. Yeah, they could be easier for an agent to write than async/await, but threads are also trivial in that matter, and you'd still need a mutex with go routines.


no, i believe it needs to be solved in finetuning. collectively, the OSS community should be pooling local LLM resources and providing a route to models that inately choose best practices as a "full stack" engineer would see them.

in your mind, you think a harness and prompt is sufficient framing to keep the LLM output to design goals. but no matter your context size, as it grows, anomolous gradients appear that try to normalize competing patterns of development.

the only real way is directly training out unwanted crosswise options.


I think you replied to the wrong comment. (Or, at least, I have no idea what you're saying.)

> This is annoying but only needs to be solved once at the start, either by the LLM or the human guiding it. A single prompt of "Set up a uv project in this directory with Python 3.13" is enough that it's never an issue again for that repo.

This isn't true. I'm mostly using python and UV with claude and it periodically decides to try to run scripts directly instead of using UV.


You can use a different pair of symbols (or pair of words, like in Pascal, or whitespace, like in Python). There's certainly nothing fundamental about them.

Also, even in C and C++, they don't indicate branching. You can place a brace block anywhere you can place a normal statement. You might use them in C++ just to delimit the extent of a RAII object. In C89 you might use a block to delay defining a variable until closer to its use, because variables can only be defined at the start of its block (although that no longer applies in C99). Conversely, though it's usually bad practice, you can use if statements and loops with individual statements.


I know it’s arbitrary and I know the symbol has been overloaded since they ran out of them, but at one time there was a certain economy and simplicity. < and > meant less than and greater than; { } were code blocks; even the semicolon was the right thing to use to break statements. I wish they had stuck to that kind of readability because I don’t know what C++ thinks it’s doing anymore.

> I don’t know what C++ thinks it’s doing anymore.

C++, when increment becomes excrement, decrement back to C.


A pair of words requires more keywords (they also tend to be more verbose) and whitespace has ergonomy issues (specially with copy-pasting). Whitespace may come with intrinsic alignment, but formatting tools do short work of that.

That's like saying we could use a totally different set of runes than our alphabet.

Yes, but why?


I think they mean breaking the line in the markup, not the output

yes, that's what I meant, indeed.

I immediately thought of the ham sandwich theorem

https://en.wikipedia.org/wiki/Ham_sandwich_theorem


Sovereign capability just means that no foreign government can pull the plug. Who cares where it was copied from?

If it were somehow legal for a company to provide MS Office (not a clone) fully in the UK with no control from Microsoft, that would also count as a sovereign capability, even though none of the code was written in the uk.

Maybe that's not how you like the term to be used but it's widely used that way and widely understood.


> Sovereign capability just means that no foreign government can pull the plug

OK, fair enough on 'pull the plug ~instantly'. But models and chips age fast. If another country can stop you getting new models and chips, this means you're sovereign in state-of-the-art AI for only a window of a year or two (maybe this will widen if model progress tails off).

If it is a short window, strategically, that doesn't seem worth much given the timelines of: a) inter-state conflict, or trade wars b) cold-start time to be able to make your own models and chips

> Maybe that's not how you like the term to be used but it's widely used that way and widely understood.

Noted. But as a data-point, the audience at the event I mentioned (various AI builders and founders) made it clear from their questions to the speaker that the 'sovereign' that sov/ai was aiming at was hollow, for exactly the reasons I've stated.


> But models and chips age fast. If another country can stop you getting new models and chips, this means you're sovereign in state-of-the-art AI for only a window of a year or two

OK, that's a fair point.


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

Search: