Hacker News new | past | comments | ask | show | jobs | submit | ExtremisAndy's comments login

"AI isn't great at creating software, but it is great at writing functions."

This 100%. In my experience (ChatGPT - paid account), it often causes more problems than it solves when I ask it to do anything complex, but for writing functions that I describe in simple English, much like your example here, it has been overall pretty amazing. Also, I love asking it to generate tests for the function it writes (or that I write!). That has also been a huge timesaver for me. I find testing to be so boring and yet it's obviously essential, so it's nice to offload (some of) that to an LLM!


I have never heard of “jq”. Oh my goodness. Your comment may have just changed my life. I cannot emphasize enough how many times I have needed a tool like this (and, yes, shame on me for not making a better effort to find one). Thank you!


As a heavy jq user and now a days also maintainer i say welcome! happy to help if you run into some problem


The syntax (and theory behind it) are really arcane, but jq is phenomenally powerful.

For websites which can publish JSON extracts, piping that through jq to get just what you want and how you want it is an absolute lifesaver.


Yeap the syntax and semantics is quite different to other languages and it really took me a long time and deep understanding to really appreciate how expressive and damn well designed it is.


Wow, I’ve never thought about that, but you’re right! It really has trained me to be skeptical of what I’m being taught and confirm the veracity of it with multiple sources. A bit time-consuming, of course, but generally a good way to go about educating yourself!


I genuinely think that arguing with it has been almost a secret weapon for me with my grad school work. I'll ask it a question about temporal logic or something, it'll say something that sounds accurate but is ultimately wrong or misleading after looking through traditional documentation, and I can fight with it, and see if it refines it to something correct, which I can then check again, etc. I keep doing this for a bunch of iterations and I end up with a pretty good understanding of the topic.

I guess at some level this is almost what "prompt engineering" is (though I really hate that term), but I use it as a learning tool and I do think it's been really good at helping me cement concepts in my brain.


> I'll ask it a question about temporal logic or something, it'll say something that sounds accurate but is ultimately wrong or misleading after looking through traditional documentation, and I can fight with it, and see if it refines it to something correct, which I can then check again, etc. I keep doing this for a bunch of iterations and I end up with a pretty good understanding of the topic.

Interesting, that's the basic process I follow myself when learning without ChatGPT. Comparing my mental representation of the thing I'm learning to existing literature/results, finding the disconnects between the two, reworking my understanding, wash rinse repeat.


I guess a large part of it is just kind of the "rubber duck" thing. My thoughts can be pretty disorganized and hard to follow until I'm forced to articulate them. Finding out why ChatGPT is wrong is useful because it's a rubber duck that I can interrogate, not just talk to.

It can be hard for me to directly figure out when my mental model is wrong on something. I'm sure it happens all the time, but a lot of the time I will think I know something until I feel compelled to prove it to someone, and I'll often find out that I'm wrong.

That's actually happened a bunch of times with ChatGPT, where I think it's wrong until I actually interrogate it, look up a credible source, and realize that my understanding was incorrect.


We were already supposed to use Wikipedia like this, but most people didn't bother and trusted the Wikipedia text uncritically.

Finally, LLMs teach us the good habits.


Yeah, I love C++ as a hobbyist programmer but will readily admit I basically use it like C but with the added convenience of strings & classes. Hardly how you're supposed to use it these days, but this is fine for my toy projects. But I can't imagine using the language professionally where you've got to be aware of best practices, modern enhancements, etc. Seems overwhelming!


This is indeed a valid question, but I think it’s largely up to the user. For me, as a hobbyist programmer that sometimes writes code at work to automate certain tasks, I use ChatGPT to quickly create boilerplate/template type code AND to learn how to do new things. When I’m asking how to do something new, I try to actually learn what’s going on so that I won’t have to keep asking about that particular issue. But yeah, the temptation to just say “thanks, ChatGPT” and move on without learning anything is certainly there and could be quite harmful to one’s overall coding skills.


I think the interesting part of that is, is there money in it? I could see it being useful for hobbyists that don't care about programming that much, but would you pay for that?


I'm trying to remain impressed and open-minded, and there's no question these things are super cool, and something genuinely exciting. And who knows how much they'll improve over the next few years? But so far, if I'm brutally honest, they have largely been frustrating to work with. I am a teacher, and I use them (mainly via APIs) to generate questions for worksheets and study guides for my students. The idea of letting the computer help me save time on creating those kinds of exercises so that I can then focus on the more interesting/challenging activities initially sounded so good, but I've found I'm completely unable to trust these systems to generate correct information. Almost every question set or study guide I've generated had at least one, sometimes several, serious errors that would have led my students astray. It does still save time, and I'm sure it will get better. But like you said, the fact that I have to constantly correct its output basically eliminates the possibility, at least for now, of using it as a tutor to teach me material that is genuinely new to me (something I was looking forward to doing). I simply can't trust it for that at this point. We'll see how things evolve.


I own one, but almost never use it. For quick, few-steps calculations I’ll use the iPhone’s calculator app. When I have more complex calculations, I almost always find myself needing to remember and label different values, so I’ll just type “python3” in the terminal and get to work ;)


I wanted to like React so bad. I tried. I loved JSX and really appreciated the way you could reuse components. That was all very cool, and I was initially quite enthusiastic about it. But for whatever reason, I just could not figure out state management/hooks. Drove me crazy. It just always felt so unnecessarily complicated compared to other languages and frameworks I've used (even vanilla JS). Now, don't get me wrong: I fully accept the blame here. I am mostly self-taught (and not even the best 'student' in that context, haha) so I'm sure I just lack the overall knowledge base/big-picture understanding to really appreciate what they've done here. I hope I'll give it another shot one day, and perhaps with fresh eyes (and maybe with the help of a patient tutor), it will all 'click'!


Hooks are IMO one of the greatest innovations in UI programming.

I'll draw an analogy.

---

Why did async/await replace callbacks? They are really the same thing, aren't they? Aren't callbacks good enough?

Async/await allowed programmers to write asynchronous code as if it were synchronous.

---

Why did hooks replace classes/imperative? They are really the same thing, aren't they? Aren't classes/imperative good enough?

Hooks allowed programmers to write stateful code as if it were stateless.

    function MyComponent() {
      const [value, setValue] = useState(false);

      const buttonClass = value ? "on" : "off";

      return (
        <button
          className={buttonClass}
          onClick={() => setValue(!value)}
        >
          {String(value)}
        </button>
      );
    }
This is functional code, without scary, hard-to-reason side-effects. Except for one limited part, which operates in a stateful way.

I argue that this is simpler than the equivalent imperative-DOM modification code, and the gap between these only increases with real programs.

This isn't just a weird "web bro" thing; the hooks paradigm is useful (in theory and practice) to every UI platform.

I even wrote an implementation (closed source) for hooks in Angular. It was lovely.


This isn't "functional code" in the sense of functional programming.

It is some pseudo DSL with hidden hard to reason mutable state.


Of course it's not functional code. Just as

    let result;
    for (const item of items) {
      result = await foo(item);
      if (result) {
        break;
      }
    }
is not synchronous code. But you can write it very close to the mental model of synchronous programming.

The same is true of hooks. The code is not stateless, but you can write it very close to the mental model of stateless programming.

That is why -- despite them being optional -- hooks have become incredibly popular.


This is the best explanation for both async/await and hooks that I've ever heard, thank you!

It also shows that although there might be some learning investment required to use the more modern version of both, it's well worth the effort. I can't imagine going back to callback-riddled javascript


what do you mean async/await "replaced callbacks"? Async/await "replaced" Promises, specifically then/catch chaining. Turns out Promises can be syntactically-sugared to imperative try/catch blocks.


Ah but if I said "async/await replaced Promises", a pedantic HN poster would correct me :/ "No it didn't replace them"


I’ll be more pedantic than that! Await is more akin to yield, the fact that it’s specific to promise resolution is a specialization of the more general function body suspension used by generators, with an extra specialization for event loop scheduling. And async just means you’re returning a promise no matter how your function exits.


hah, good point. Just wanted to point out that callbacks and async/await are different things, and callbacks are still the preferred way to customize behavior.


Hooks use a different paradigm, which is a solution to a problem you encounter when doing functional programming, which is persistence and side effects. The whole of React is to build a tree of objects that will be rendered into a HTML page. The previous class-based architecture made it easy to store state and add side effects to this tree, by using properties and methods. But pure functional programming makes these awkward as functions are transient, only transforming parameters into return values.

I don't know exactly how – never had the time to properly research it – but, my current guess is that the hooks code taps into the scheduler/dispatcher – which handles the execution of the function representing the component – and stores value and logic somewhere. It uses the order of these calls as keys – you don't have to specify them – and provides the stored values as return values of the call of the hooks functions.

Hooks are escape hatches from the functional paradigm of React's components. You are always providing new values, and it decides when to store the updated version – mostly based on the deps array. You then get back what you stored. On the surface, it's still basically functional, but the actual logic is not. It's more like a repository of code and values.


One view of Hooks is that they are monadic or at least Monad-like and the deps arrays are a crude (reversed) notation for algebraic side effects. ("Reversed" because they declare which dependencies have side effects more than they declare which side effects the hooks themselves produce.)

It's still so very functional programming-inspired, even if the execution engine (scheduler/dispatcher) isn't that much like the Monad runtimes of most functional programming languages and the various Hook "monads" don't get captured in even the return type of functions (much less the parameter types) and get elided away. (It could be more "traditionally JS monadic" if it [ab]used async/await syntax and needed some fancy return type, even though the concepts for hooks don't involve Promises [or Futures, being the slightly more common FP Monad name]. Though also, from Typescript patch notes, I've heard React is exploring [ab]using Promises for something like that in the near-ish future.)

Monadic bindings needing to be in-order, just the like "Hook rules", isn't even that strange from an FP perspective: there can be a big difference in which of two Promises is awaited first. There can be a big difference in which IO binding executes first (you don't want to input something before the prompt of what to input is printed).


All hooks are based on useReducer. Whenever a component is rendered React sets a global (!) variable for the current component. They didn't even bother to have the component be a parameter into the hook to get rid of the global variable. No, it must be pretentious and claim to be something it isn't. The global variable stores a linked list with the hook data. The calling order of your hooks matters.


I find the hooks so much easier to use than e.g. Google's ViewModel solution in Jetpack. They are just a joy to use.


Don't blame yourself. Software engineering tools are supposed to serve the programmer, not the other way around. If a tool is too hard to use, then you're using the wrong tool. Tools should serve the developer. I would recommend plain old javascript with a light wrapper on top, like jquery. I know i'll get downvoted for this but a lot of "modern" javascript frameworks don't properly abstract the underlying layer properly (read Joel spolsky's article on leaky abstractions) and this results in a lot of problems. Furthermore, they optimize for the wrong thing: writing code. Most engineers spend 95% of their day reading code and that's a lot harder than writing code.


it's true, React, Angular and other popular heavy frameworks aren't designed to serve the programmer, they're designed to serve the organization that owns the codebase by making turnover easier. They force a specific approach and layout new hires can be familiar with, regardless of if it's even a good idea for the application at hand.


With all due respect, this sounds like a "old dog"/"new tricks" scenario.

"What's this .map() nonsense? The indexed for-loop always made sense to me."


There are certainly benefits from doing things in new ways, but a lot of the time things swing too far in the opposite direction, and become of a form of “IQ signalling” for smart developers.

It isn’t only front-end developers who are prone to this: 20 years ago, before FP became a mainstream thing, being able to do pointer arithmetic was seen as the differentiator between a “smart programmer” and a “bad programmer” (https://www.joelonsoftware.com/2006/10/25/the-guerrilla-guid...).

Was React great and fun to work with? Yes, but then Redux came along and made something simple into something stilted. Our team used Mobx instead, which was simpler IIRC.

Similarly it’s been a couple of years, but I remember React Hooks being a bit complicated for the value we got out of them.

Ultimately, it’s hard to tell if something is an improvement, or a time suck to allow the elites to stand out. I stopped playing the game and stepped away from front-end development, as have many of my experienced colleagues.

I’m assuming things have settled as Big Tech focusses on profitability rather than funding an endless parade of frameworks, and the IQ-signalling will become less prevalent as generative AI competes with the brainiacs. When that happens, I’ll dip my toes back in the world of front-end development.


Redux has never seemed like a great solution for the programs I've written.

Though FWIW, MobX is far more magical than hooks.


well, those new tricks are going to bite you, later on down the road.


Hooks are half of an object/class system (implemented on top of a language that already had a whole one—arguably, two, from a DX perspective, though they're one under-the-hood) with non-standard and hard-to-read declaration syntax and bizarre behavior (FIFO-by-declaration-order property access and method invocation). It's not your fault you're having trouble with them, they're a weird boondoggle.


view = func(state).

That’s the magic of react. The problem is no longer manually managing transitions between state but state itself.

That’s why state management is so critical in the react ecosystem.

Further, react has delegated two key features to userland: side effect and state management.

Personally, I don’t want react to solve either of these problems because it’ll just turn into the disaster that is react server components: feature development driven by corporate interests (eg vercel).


> view = func(state).

If this was actually how it worked, I'd have much less problem with react. What I mean, specifically, is that not all function dependencies are explicit. This makes it look like the state is passed into some function. And then the view is returned, depending only on state. In reality, half the state is passed in (as in the argument to a function call), and half comes out of some mysterious hook storage structure. If the state was really a function argument, you could easily inspect the whole state in a debugger. Instead of... I'm not sure how you'd actually do that.


This brings up other questions too. Is the state on the client? How does one reconcile the server state and the client state. Is the client state a subset of server state? Is the client state a tree matching the view tree? Does the state contain only the UI data to be rendered or is it all app state.


React Developer Tools makes it easy to inspect component state in your browser. https://react.dev/learn/react-developer-tools


> it’ll just turn into the disaster that is react server components: feature development driven by corporate interests (eg vercel)

if you've followed along with the react team's discussions on server components, it is very clear that vercel implemented the react team's vision and less so the other way around.

as someone who has been using them extensively, I understand why. they're delightful.

vercel does control next.js which is the only framework to completely implement RSC, but as other frameworks catch up, RSC will have a wider surface area.


I think that view = func(state) is an unnecessary complicated way to describe frontend development.


After years of react dev that is probably one of the wildest takes I’ve ever read. Kudos!


Hardly a wild take though, is it? You're in the context of "I am mostly self-taught (and not even the best 'student' in that context, haha) so I'm sure I just lack the overall knowledge base/big-picture understanding" and you come in and say view = func(state).

Here's how the React docs introduce it:

"React is a JavaScript library for rendering user interfaces (UI). UI is built from small units like buttons, text, and images. React lets you combine them into reusable, nestable components."

Hopefully you can appreciate the difference.


Hooks are complicated, but state/props is just right. Both enables you to enforce boundary and make contained components. If props and state are mixed / diluted, the component won't know when to do re-render and there'll be too many things to track, and there'll be many classic issues such as cyclic dependency and sluggish performance of two-way data binding.

Hopefully you'll click on it someday


1) React has no state management - approach it not from what it should be, but what it is - a tree of components that just render their props and where each component has some internal state.

2) Components have behavior. In Class based components they were implemented as methods. Simple enough, classes have methods. If you think about an iteration of rendering the ui tree, it goes down the tree and calls the mount method for each component in the ui. With hooks, instead of calling a method on an instance, it's implemented as an inner function of a component that is also a function instead of a class. Instead of explicitly calling the mount method on a class instance, calling a function that's a component automatically runs it's inner mount method. The way that it knows the which inner function is a lifecycle hook is because you import something like 'useEffect' from the react library. And that global useEffect function knows the current component because the renderer sets it as it's going down the ui tree. Hooks are better because they can be written as arrow functions (more concise, cleaner), and because you're calling a framework function, that function can have more complex behavior like how useEffect can track when to update because it's being passed in an instance of something like an internal state variable.


I've been using Preact signals, which are also usable in React (though admittedly I haven't tried to use them). I've found them to be much more pleasant than useState (though I reflexively continue to use useState). I also use a pretty lazy pattern where I allow large portions of an application to rerender when state changes (implicitly by letting prop changes percolate through). For simple apps this works really well, and for complex apps it still works. Like I have an app with 200Mb of rendered DOM nodes that get rerendered from the root when anything changes, and it's totally fine. I wouldn't ship that app widely, but for internal use it's 100% fine.


I’d be interested to know if NakedJSX works for you. I released it about 6 hours ago and I'm looking for feedback. It allows you to use JSX (without React) to generate static HTML, and also to create DOM nodes in client JavaScript, and without any of the client side ‘framework’ stuff of React. You have full control over what happens when.

https://nakedjsx.org/documentation/#getting-started

EDIT: clarity


I think there's a niche for libraries that allow you to update the DOM declaratively without any requirements on how you manage state. My understanding is that React looks at props / hooks in order to diff the state of your app and selectively recompute the virtual DOM. An alternative is to naively recompute the entire virtual DOM. I think this is how Mithril.js does it? It may be less efficient for large apps but it lets you manage state however you like.


I always use it while developing a new web app, but admit that I always switch it to something "fancier" in production, mainly because I find alerts rather ugly. But, goodness gracious, it would simplify so many things! I've just sort of assumed that default browser alerts were considered a big no-no these days, but that assumption comes from the fact that I simply don't see them being used much. I guess I should look into this more. Sure would shorten dev times!


No idea about Go, but I was curious how GPT-4 would handle a request to generate C code, so I asked it to help me write a header-only C string processing library with convenience functions like starts_with(), ends_with(), contains(), etc.) I told it every function must only work with String structs defined as:

struct String { char * text; long size; }

...or pointers to them. I then asked it to write tests for the functions it created. Everything... the functions and the tests... worked beautifully. I am not a professional programmer so I mainly use these LLMs for things other than code generation, but the little I've done has left me quite impressed! (Of course, not being a professional programmer no doubt makes me far easier to impress.)


Interesting. I haven’t tried it with C. Hopefully the training code for C is higher quality than any other language (because bad C kills). Do you have a GitHub with the output?


Consider applying for YC's Summer 2025 batch! Applications are open till May 13

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

Search: