Libs arose in static languages. They save effort recompiling common code. But you only save compilation time if libs are more stable than non-libs. If libs are islands in your sea of code.
In the desktop era libs were units of commerce. To sell a library you promised 'code reuse'.
But code reuse is still a mirage. Upgrading a lib remains akin to transplanting an organ into a new body. Always the fear of rejection.
As libs mature upgrades get smoother, but at the cost of degrees of freedom. Constraints are only added, never removed.
Let's try backing off from the mirage. We have dynamic languages now, no compilation. We aren't trying to sell code. Let's not get hung up on backwards compatibility, on breaking the code of others. It's often easy to fix. Just make sure code screams when it breaks. Unit tests, etc.
Let's try keeping code from others in the same directory as our own. Rather than segregate it into a separate ghetto, let us hack on it like it's our own.
Any codebase will form islands over time. That doesn't make solidity a virtue. Let us not prematurely generalize interfaces.
But code reuse is still a mirage. Upgrading a lib remains akin to transplanting an organ into a new body. Always the fear of rejection.
For the same reason as that, I don't especially believe in upgrading libraries. If that's code reuse, I agree it's a mirage, but my idea of code reuse is just to use the same code as someone else has used.
---
Constraints are only added, never removed.
Are you sure? A library that prides itself on perfect backward compatibility will only remove constraints and add features, never the reverse. Or are you talking about the fact that sometimes new features are limited in seemingly arbitrary ways because that's necessary for them to be able to cohabitate with features that came before?
---
Let's not get hung up on backwards compatibility, on breaking the code of others. It's often easy to fix. Just make sure code screams when it breaks. Unit tests, etc.
I agree. Fostering a community is probably easier when maintaining backwards compatibility, but I prefer the idea of encouraging people to use whatever version they like.
Let's try keeping code from others in the same directory as our own. Rather than segregate it into a separate ghetto, let us hack on it like it's our own.
...Then again, as waterhouse points out at https://arclanguage.org/item?id=13260, fostering a community is probably easier when there's a single standard basis everyone's using.
Another advantage to segregation is that occasionally the organ transplant does work, and then you've spent minimal effort to catch up with the community and the cutting edge.
Furthermore, the strategy you're talking about sounds like a practice that already exists to a degree (in blogs and forums) and can be promoted in any language, so I'm not worried the languages will get in your way here. Of course, lots of things are doable in many languages but are better suited to certain ones. Can you think of any particular language features that help out, besides modules? Any that become less important, besides modules? :-p
---
Let us not prematurely generalize interfaces.
I don't know what to tell ya. Sometimes I'm not sure I make anything but generalized interfaces. :-p
Saving keystrokes on kindle makes me seem certain :)
Also can't read pdfs on kindle for a few days.
I meant constraints for lib implementor. Libs rarely delete stale features.
Upgrading libs is simply the most obvious pain point. Successful upgrade is worse, causes complacency. Using abstractions without understanding is cargo-culting. We've all done it.
Easier to learn up front than debug later, to learn in isolation than in a big system.
I can try this in arc because: it's dynamic; few and concise libs, less catching up; we've often ignored bc.
Community is lower priority for now. Let's see what happens.
Successful upgrade is worse, causes complacency. Using abstractions without understanding is cargo-culting. We've all done it.
I accept the risk of not being an expert in everything I'm using. Otherwise I'd never attempt anything, and I'd never learn. :)
It does go against my grain in a certain way: I like to build things that are precisely what I want, so it's bothersome for those things to depend on anything I don't control. However, usually I don't care about the whole codebase being precise, just the observable outcome of it.
---
Easier to learn up front than debug later, to learn in isolation than in a big system.
I think that's the opposite of your point. I take it by "big system" you mean a large group of concepts with so much interconnectedness between them that it's hard to understand any one concept before understanding them all. But you've mainly been saying you'd rather people not think of each other's code as being separate from theirs. That you'd rather have all the code in a project be developed as one big system.
Well, maybe your ideal scenario is for each borrowable codebase to be a small system, such that people can easily learn it and integrate it into their big-system applications. But what about a borrowable codebase that depends on another borrowable codebase? If that project treats the depended-upon codebase as its own code, it'll become a big system, and it'll be harder to borrow. If instead it just comes with advice about what dependencies to track down to get it to work, it's back to cargo-culting.
Also, if my own application is a big system (thanks to all the borrowed code I've added), that's bound to be annoying to me when I try to understand it in six months.
---
I can try this in arc because: it's dynamic; few and concise libs, less catching up; we've often ignored bc.
The last two are probably related. :) With a smaller quantity of well-borrowed code to break and with more of it being easy to fix, there's less short-term value in preserving backward compatibility.
I agree about it being healthier not to promise or rely on backward compatibility. I think there is a language trait that can actively help with that: hackability. If my code can load versions two and three of a library and patch them together, then I don't have to go patch them together on a textual level and drastically increase the amount of code and complexity that belongs to my project.
Of course, even with hackability handy, it's still possible to take full ownership of certain pieces of borrowed code when it makes more sense to do that, so it's not like we have to choose. :) And both of these approaches are taken in Arc programming already.
---
Community is lower priority for now. Let's see what happens.
Well, I consider myself to be programming for the community of all my future selves. ^^ It's 'cause I have a lot of concrete project ideas that are too grandiose for me to have fun working on right away. In the occasional case I decide to implement one of the more urgent or less fickle ideas, it really pays off that I've amassed a lot of abstract, future-proofed libraries in the meantime. So I'm often interested in developing things that make future-proofing itself easier, like module systems. Ironically, they have the most immediate use for me.
There is no borrow. When i see external code that may be useful to my pgm i want to understand it, tailor it for my needs, prune the unnecessary.
I want to see how long I can keep the codebase small.
You don't return to all your code. 90% of my code never gets read again. Not worth thinking about.
When I do return to old code I lately have no trouble. I think it's the unit tests. Little easily digestible atoms of semantics.
If everyone does this less code will be shared, but shared code will become more timeless. Easy to return to it in six months.
You don't have to be an expert in other people's code, design decisions, error paths. Just concepts and happy paths. So you see opportunities to delete.
Perhaps borrowing code is also learned from static languages. Just a delete-if loop in c can be nontrivial to read.
We're really getting to the heart of things now, I think. :)
---
There is no borrow. When i see external code that may be useful to my pgm i want to understand it, tailor it for my needs, prune the unnecessary.
That's one kind of borrowing, as far as I'm concerned. All I'm talking about is tech one person comes up with first and another person takes advantage of. Whether it's called code reuse or borrowing or whatever doesn't matter to me.
Borrowing code is essential for arriving at the best combinations of ideas. Two heads are better than one and all that.
---
I want to see how long I can keep the codebase small.
I want my code to be small only because I want it to be valuable to me when I go back to read it. Value comes first.
And on that topic...
You don't return to all your code. 90% of my code never gets read again. Not worth thinking about.
...if I believed that, then maybe I wouldn't even care if my code were small. :)
I return to my code more and more as I've developed better tools to future-proof it. If any piece of code isn't worth returning to, then why was it written in the first place?
Okay, maybe for one-shot scripts or something. ^_^ Like I said, I primarily write abstract, generalized code (or at least that's what I perceive I do).
---
When I do return to old code I lately have no trouble. I think it's the unit tests. Little easily digestible atoms of semantics.
Comments are good for that too, but unit tests are certainly easier to keep up-to-date. :)
---
If everyone does this less code will be shared, but shared code will become more timeless. Easy to return to it in six months.
You don't have to be an expert in other people's code, design decisions, error paths. Just concepts and happy paths. So you see opportunities to delete.
I think we're on common ground here. ^_^
---
Perhaps borrowing code is also learned from static languages. Just a delete-if loop in c can be nontrivial to read.
What do you mean by a static language? You keep referring to static and dynamic languages, but in my experience "dynamic language" is a term for a language with dynamic typing. I think C loop boilerplate is something to blame on the lack of a convenient closure/block syntax, not the type system.
If by "static language" you mean a language that can't be changed, that makes way more sense. But even in a language like Arc that's open to customization, we still share code.
Actually, you probably mean something different by "borrow" too, such as using code as a black box. In that case, you make sense again. :-p
The full translation is "Perhaps the practice of taking code for granted has come from a history full of languages where code isn't formatted in a personalizable enough way for its purpose to be clear." I don't want to put words in your mouth, though. XD
"Perhaps the practice of taking code for granted has come from a history full of languages where code isn't formatted in a personalizable enough way for its purpose to be clear."
Yep. There's more pressure to take code for granted in languages so verbose that everything is non-trivial to read. It seems to have been a slippery slope from having such languages to assuming take-for-granted-ability was an unabashed virtue.
That is perhaps the biggest disadvantage of C and relatives[1]: they kept programmers from bulking up on their reading muscles, the ability to read concise code patterns at a glance. Perhaps this is partly what Dijkstra was referring to as 'brain damage'. (https://www.cs.utexas.edu/~EWD/transcriptions/EWD04xx/EWD498....) [2] Fortunately it is curable, no matter what he said.
[1] What I was referring to as static languages, where functions can't be redefined dynamically.