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

Eh, most of the time you do have to publish it. MIT/BSD/Apache allows you not to, but most big projects are using LGPL or another share-alike license. With those, if you're making a project that you do publish (e.g. a commercial product that uses that library/language/etc.) you do kinda legally have to share that modified source code. It's of course different if you're scripting for your own sake, but the moment you publish anything using them you also have to publish your modified versions of libraries and other stuff.

I do agree with the "fork and make it better for you", but I also think it's common courtesy to throw up issues for the bugs or missing features you encounter, as well as pull requests. If for no other reason then as "prototypes" or "quick fixes" that others can cherry-pick into their own forks. They may get rejected, they may get closed, but you still don't have to sit there arguing about it since you have your own version. From a slightly Kantian angle you have your working version and you've now fulfilled your social duty by offering solutions to problems. You've got no need to campaign for the solutions if they get rejected.

It's virtuous and you get to ignore the github flame wars. There's really no downside beyond taking 5 minutes to be nice and at least put your solution out there. Also fulfills your reciprocal legal duty under LGPL and such.


I think the best way to go (if you're the "Good Samaritan Who Wants to Do His Civic Duty but Also Doesn't Want to End Up Spending the Week in Nerd Court") is to fork it, fix it, and leave a brief comment in the issue thread that says "hey, I fixed this in my fork".

That way, people with the same issue who come in to the issue thread through a search aren't reduced to combing through all the forks to see if one happens to fix the issue. Then instead of spamming up the thread with "me too, this is soo frustrating, fix asap pls", they can spam it up with "merge this fork into the main project asap pls" :-)


If you don't distribute to others you don't need to distribute your own changes even for copyleft licenses. That's why the AGPL license was written, because if you're doing something as a service you won't need to distribute any sources even with GPL license.


> you do kinda legally have to share that modified source code

I'm using the license exactly as intended. Upstream developers literally don't matter. Free software is not about developers, it's about users.

Free software licenses say the user gets the source code. They're about empowering the user, in this case me, with the ability use and modify the software as I see fit. If I customize something for my personal use, then I'm the only user of the fork and license terms are fulfilled. People would only get to demand source code from me if I started distributing compiled executables to other users.

> You've got no need to campaign for the solutions if they get rejected.

I used to feel that need. Caused me significant anxiety. I thought upstreaming patches was the Right Thing to do. Mercifully I've been cured of this misconception.

> There's really no downside beyond taking 5 minutes to be nice and at least put your solution out there.

I have no problem with that. My point is getting involved with upstream is often more trouble than it's worth. Let them do their thing. Just pull from them and rebase your changes. Enjoy life.

People should think twice before trying to cram their unsolicited code down other people's throats. Even when they ask for the code, chances are deep down they don't actually want to deal with it.


That is exactly why I said that that only comes in once you publish something. The legal argument isn't as strong as the moral one is for me anyway, I never publish anything. I think making a PR isn't forcing code on someone, they're not obligated by anything to read and consider it, but if they do want to they can. I'll make one, and then I'll stop responding, because that's where my personal moral obligation ends. Whoever wants the code can now easily discover it, whoever doesn't can throw it away as they like. Including the upstream maintainer.


Usually better start with small scale fixing typos and improving docs. That’s great canary for me. If it’s accepted within day or so, that’s project which I willing to learn. I would say you can select projects for your value and you would be fine contributing there. Eventually people will learn you and will trust you more


I understand your point and it's good advice. Typos and documentation though? That's boring... I want to do interesting things. Ever wondered why some program can't do something? Surely someone much smarter would have thought of it, right? And then you code it up and it actually works? That's the kind of thing I like to do.

I once tried to retrofit a library system into GNU bash of all things. Let's just say it didn't go well.


Your patch sounds horrible, no wonder people reject them.


Works for me. I can easily organize and reuse functions now. Made scripting much more pleasant. Even made a package out of it so I could install it alongside the upstream version.


That'd be a nice way of looking at it, if serving content was cheap. It is not. I want to put my CV online, but I'm not willing to shill out tens of thousands every year to have it scraped for gigabytes per day. Doesn't happen, you say? Didn't before, definitely. Now there's so many scrapers building data sets that I've certainly had to block entire ranges of IPs due to repeated wasting of money.

It's like the classic "little lambda thing" that someone posts on HN and finds a $2 million invoice in their inbox a couple weeks later. Except instead of going viral your achievements get mulched by AI.


I have a personal website (including my CV in PDF), blog, and self-hosted email. A story I posted once made the HN frontpage and my e-mail is in my profile, meaning my content is read by more bots than humans.

My monthly hosting costs are ca. $10 a month. Therefore I'm really curious: if hosting your CV requires "tens of thousands every year", what does your setup looks like?


I imagine it is something about bandwidth costs


Gigabytes? How big is your CV?

>lambda thing

I never understood why anyone thought this was ever a good idea. QoS is a natural rate limit for non critical resources.


Putting stress on the concrete requires force, and causes the concrete to deflect. Force over displacement is work, and energy can't be lost to nothingness by just breaking the concrete. Thus, the concrete releases the stored up energy as kinetic energy of its fragments.

Stronger concrete requires more stress to cause it to fail, and as such it takes more force to break it. There is logically more energy because of the higher force, so more energy gets released.


more than 3 chips, basically


Forget everything, we're doing 5 chips


Yeah, C++ enums are just numbers that are really good at pretending to be types. And for that reason they're not actually objects that contain things like their name. And they probably shouldn't, in the vast majority of cases it would be an utter waste of space to store the names of enum members along with them. So you have compile-time reflection for those instead. And yeah, you could implement some kind of thing pretending to be a member but actually being a reflection thing but that's both horrifying and limited so C++ takes the reasonable approach of just adding general reflection in instead.


wow that's really evil of them i quite don't like them for this as i too played garrys mod back in the day and it pains me to see such a loss of community effort and beloved mods


It's not like they're demanding the deletion of all mod content as the headline carelessly implies. Yes it's boring and corporate but I don't think it rises to the level of 'evil.'


Why not?

Destroying harmless creativity and amusement culture is evil.


It sort of isn't though. You put it there and you don't take it away. You don't put anything else in there to load it. It stops loading entirely if you take out the ethernet cable. That kind of seems like it's loading from the internet every single time. The setup function doesn't add anything to load it without the init script running. That's kind of weird, to me at least.


Oh, I didn't mean to imply it was a good way of doing things, just that the intent was to auto-update. Regardless of how the auto-update works, if a program like this is auto-updating then you're giving arbitrary execution permission to the project.


In Linux there is a package manager for auto-updating.


Whatever Neuralink is missing, it's none of these things. They're certainly missing a lot, as is their owner, but it's absolutely none of these things. Like, we've been using brain electrodes to control devices for a very long time now. They know the issues. As they are originally a neuroprosthetics company whose whole goal was to develop means for paralyzed people to control limbs and devices, they're perfectly in their zone. That's not their issue.

As what their owner wants them to be, with data transmission into the brain and individually addressable neurons, they're leagues off from a functional product. Extracting and interpreting brain signals is, while not simple, well-known and well-practiced. The other direction is practically unexplored and the most we normally do is poke around with a bit of electricity and hope it makes the brain work better. To move data from a computer into the brain would be a total revolution. Needless to say, their current product does not do this, and they've shown zero development to this end. Which kind of makes it feel like they're hoodwinking Musk to develop actually useful medical devices instead of playing into his naive technocratic futurism. That just means they know what they're doing even more strongly than what their other actions have already shown.


> Extracting and interpreting brain signals is, while not simple, well-known and well-practiced. Their current product does not do this, and they've shown zero development to this end.

I was following you until this. Can you clarify? Isn’t their most recent work precisely an example of inferring and applying a person’s intent by deciphering their brain signals?


Ah, sorry, one of those situations where you think about what you'll write and don't end up writing it down. I am of course referring to the inverse in the second sentence, moving data into a brain from a computer. Corrected in the original comment now, thanks!


I don't think currying happens without you asking to, though. It happens because it happens, it's part of the language, and it's something you implicitly keep in the back of your mind every time you see a function call. I don't program a lot in Haskell, only some maths things I sometimes might need since it is rather useful for that, but the concept of currying is so natural that it's constantly expressing itself in the code. Very rarely do you apply arguments and consider that to be a function call in itself instead of like, three function calls. And since partial application is so incredibly important to Haskell and other similar languages, without currying writing would be very difficult. Consider the actual simple example of

      gears = filter ((==2) . length)
            . map (neighbouringNumbers numbers)
            $ filter ((=='*') . fst) symbols
which without currying would have to look like

     gears = (\xs -> filter ((\x -> x == 2) . length) xs)
           . (\xs -> map (\x -> neighbouringNumbers numbers x) xs)
           $ filter (\(c,_) -> c == '*') symbols
It just makes partial application a lot easier, especially when this kind of code pops up all over the place.


> I don't think currying happens without you asking to, though. It happens because it happens, it's part of the language, and it's something you implicitly keep in the back of your mind every time you see a function call.

Eh, but that's my point: I want less cognitive load. Currying is another thing that I have to keep in the back of my mind, and Haskell already has way too many of those, and it's not a particularly useful thing. I've got limited space in the back of my mind for things and if I'm going to keep things in the back of my mind I want them to be useful. I mean, if your argument in favor of currying is that it saved you a few keystrokes in that example, color me unimpressed.

Maybe I'm just too stupid to understand easily, but the "simple" example you're giving is taking me a while to understand. If a junior dev on my team submitted that in a PR I'd send it back asking them to break it up into a few smaller named functions and probably not use a partial application at all. Something like "I know it's fun to be clever but let's make this easier for the next person who has to figure out what it does".

I guess what I'm saying is that for that example it seems like you're going for tersity rather than clarity for future readers of the code. If you were going for clarity you probably wouldn't write it either of the ways you've given.

And in big projects clarity is the number 1 concern[1]. In toy examples like this I can slog through and figure something like this out, but when it's 30 functions written like this, all calling each other in the most clever ways possible, nobody can figure it out.

[1] EDIT: Okay #2 after correctness perhaps. But it becomes hard to achieve correctness without clarity as a project grows.


Hi, as someone who has been interested in functional programming for a while but who struggled to read point-free Haskell code until recently, I think it might be useful to share my perspective.

      gears = filter ((==2) . length)
            . map (neighbouringNumbers numbers)
            $ filter ((=='*') . fst) symbols
If this Haskell code does not look clear, it's because people are unfamiliar with point-free style, not because the this code is badly written, and especially not because the reader is stupid.

The given Haskell code reads naturally to me now. (I'm only a little uncertain because I can't write Haskell.) It would have been line noise to me before before point-free style clicked.

I tend to read Haskell code in articles from right to left, and it reads: "Choose the symbols whose first letter is '*', get their respective (neighboringNumbers numbers), and choose the results whose length is 2". I read (neighboringNumbers numbers) as if it were a noun.

I don't know how this clicked, but I'm pretty sure it has nothing to do with stupidity. Perhaps it was by chance, or perhaps it was by banging my head against the wall enough times.

Would I introduce point-free style in a JS codebase? Probably not. People are unfamiliar with this kind of style. Would I introduce this style in a Haskell codebase? Almost certainly, because it's clear and I think it reflects how Haskell programmers think.


They say that array languages are pretty readable once you get used to them, too? But you’re drastically limiting your audience. Part of readability is writing for people who aren’t as fluent as you are.

Expert jargon can sometimes be useful, but it often obscures things that would be pretty simple if written some other way.

With Haskell there’s a tension between saying “I only care about writing for other expert programmers” and “more people should learn Haskell.” The idioms are part of the turnoff.


It's not really saying "only expert programmers" though, is it? It's people who know Haskell, which by coincidence happens to be overzealous undergraduates and a certain subset of experienced programmers. FP is a paradigm among many, its basics somewhat predate (or since it's so close, co-date?) more imperative descriptions of computation. That we mostly use and as such mostly teach beginners with procedural languages is a quirk of history. Nothing would prevent a change to that except historical inertia. Saying "more people should learn Haskell" is saying "I don't want to write code only for other expert programmers." It's just as natural if you know it, and even beginners could know it, they just don't.

However as I mentioned, since it is not true that most people can read FP code, I mostly avoid using it. The example comes from my solution to AoC2023's Day 3, "Gear Ratios", which is just about the only thing I use Haskell for.

That doesn't mean that using it doesn't have practical applications, since being used to multiple paradigms opens you up to unconventional solutions. I've recently sped up a MATLAB function ~100x through using a more functional style to manipulate memory more efficiently. Async/await, certain styles of modern iterator manipulation and generators escaped F#, CLU and others into C# and from there into the world at large specifically because Microsoft programmers saw a problem they had had a solution for in previous functional projects. So it's not all useless.

For the record, a more imperative version could be written as

    symbols = [ imagine there's stuff here ]
    gears = []

    for (symbol, coord) in symbols:
        if symbol == '*':
            ns = neighbouringNumbers(coord) 
            if len(ns) == 2:
                gears.append(ns)
or in Python's functional-inspired notation which directly mirrors what's happening in the Haskell code

    gears = [ neighbouringNumbers(coord) 
              for symbol,coord in symbols
              if symbol == '*' and len(neighbouringNumbers(coord)) == 2 ]
though that requires an unnecessary extra call to neighbouringNumbers, which you could solve with a walrus op but I can't remember how to do that. I also changed the entire pair being passed to neighbouringNumbers (which was convenient in Haskell) to only the coordinate that is required (which is convenient in Python).

Personally I just find nowadays that having to comprehend "it collects neighbour-pairs from '*' symbols" from the imperative code harder than having that be the thing that is actually written down.


It’s true that readability is culture-specific, that if the culture were different and people learned different things then different languages would be more readable. But I still think there are differences between languages in the sense of how much you can understand without knowing the definition of every term.

For example, if you’re looking at Lisp code and you don’t know whether an outer term is a function, macro, or special form, you really don’t understand anything inside it except at the most superficial level. It might as well be JSON. Macros aren’t marked, so any unknown term might be a macro. (Knowing the surface syntax is still helpful, though. Well-known syntaxes for data are useful.)

With Forth it’s pretty bad, too. Not knowing what a single word does means that you don’t know what’s on the stack afterwards.

A Unix pipeline is a bit more orderly since you know that there are streams of bytes. You know the command names and the arguments to each command. But if you don’t know what a command does, you don’t know much at all about what the data looks like after that point.

I find currying and point-free programming to be pretty opaque because I can’t tell where the function calls are or how many arguments each function takes from usage. I don’t know what the dataflow looks like. It seems like you need to know some precedence rules too?

Languages with conventional function call syntax, augmented with named parameters, seem better. I can tell where the function calls are and where the inline functions are. Augmented with reasonable names for temporaries, I can make reasonable guesses about what the code does.

These syntax concerns seem independent of whether it’s a functional or imperative language? Making reasonable guesses is what we do when we read pseudocode. Maybe what I’m saying is that some syntaxes seem better for pseudocode than others, and I like languages that look like pseudocode better.

I suspect that these syntax differences also have an effect on how good the error messages are when you screw up.


> you really don’t understand anything inside it except at the most superficial level

This is true, but:

- the name of the operator is typically a word that you can easily search for in the documentation or on the web, or with "jump to definition" in your editor, if it's something locally defined in the source tree.

- you usually understand the shape of what is inside it. You know what parts of the program you are looking at are arguments to that mysterious operator and which are not. If asked which expression is the third argument of that operator, you can easily find it and know where it begins and ends.


> Macros aren’t marked, so any unknown term might be a macro.

Yes, that's a problem.

There are two clues:

* Macros typically have naming conventions. For example anything beginning with DEF should be a defining macro, not a function. Anything with DO- will be a control structure. Anything with WITH- will be a scoping macro. And so on. Avoid active names like CREATE- and use DEFINE- instead. CREATE-CLASS would be a function, DEFINE-CLASS would be a macro.

* In source code the enclosed code typically has syntax and special indentation, when used with macros. Functions have certain uniform indentation rules.

    (create-class 'container-ship
                  :superclasses '(ship)
                  :slots '((max-number-of-containers :type integer))
                  :documentation "our new container-ship class")
Above is a function and uses one of the typical formatting/indentation rules for functions. Line up the arguments. Start with the required argument and then the named argument pairs (name, arg).

The macro looks different. The first important things like name and superclasses are on the first line. The other parts of the class specification follow and are indented by two characters.

    (define-class container-ship (ship)
      ((max-number-of-containers :type integer))
      (:documentation "our new container-ship class"))
Developers who write macros should make it clear what a macro is, by using hints like these.


I guess my bigger complaint in this example is that there's a lot left out. What's in `symbols`? What is each `coord`? What does `neighbouringNumbers` do? What is this function trying to do?

I write Python a great deal for a living these days and the Python code isn't much clearer to me. In both the Python and Haskell examples I can tell what it's doing (except the opaque neighbouringNumbers)--I just can't tell why it's doing it.


It is in most places. At least in Europe where I live there's a limit of 12 years old for cycling on sidewalks and pedways marked with only a pedestrian sign, whereas sidewalks which are wide enough and marked with both a bicycle and pedestrian sign as well as paths marked with both a bicycle and pedestrian signs are for pedestrians and bicyclists equally. And of course this has its logical conclusion in bicycle-exclusive bike lanes and bike paths with no pedestrians at all on them. It's especially no issue if everyone gets the rules, generally on wide sidewalks where bikes are allowed the outer side with buildings is for pedestrians and the inner side near the road is for cars. Where no bicycle-OK sidewalk exists you just use the road or walk with the bike.


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

Search: