OTOH, it took around 15 years to get there. I understand that this kind of dedication may not be possible or worth it for everyone.
[1] Because there is very, very little unique features to each language. Unless you go to the fringes, you're bound to see the same concepts applied again and again and again, which gets really disheartening after a while. If you don't believe me, try naming any "new" feature which was added to your favorite (EDIT: I meant mainstream - TIOBE top 10 or 20 - lang here!) language recently - and I'll show you that same feature implemented 10 or 20 years ago in another language(s).
EDIT: more neutral wording.
What I do doubt, is that it's possible to know several languages in-depth and at the same time be at least very good in a specific domain (webdev & mobile apps are not domains), have good algo and problem-solving skills, have decent to good soft skills, know at least a little bit of PM and also be a good conversation partner and well informed citizen of the world, while also being a good husband/wife/dad and being reasonably competent at some hobby that is hopefully not related to computers.
Learning and keeping up to date with the N+1th language takes space from learning the many other interesting things this world has to offer.
My choice was to forgo any hobbies unless they are somehow useful for programming, ignore most of being "well-informed citizen of the world", ignore the whole mating and breeding business and to focus solely on programming at first, then on programming-related fields that picked up my curiousity. I'm still competent enough in other programming- and work-related areas - at least I've never been told otherwise - but, indeed, half of what you write about is nonexistent in my life.
Actually, if there was a monastery for programmers, with ascetic lifestyle and good broadband connection to the Internet, I'd go there in a heartbeat.
OTOH, I don't think you'd need to go to such lengths normally. As a programmer, you'll be working for 40 years at least, right? 30 minutes of reading a day will eventually get you to the respectable N (if you choose this particular field), it'll just take longer.
The OP said the fact that he learned multiple languages makes him fall behind his peers in coding tasks. I'm saying that he would have no such problems had he learned these languages in-depth and it's perfectly possible to do so. I admitted immediately that the effort needed for this is at least substantial, no disagreement here - I just pointed out that, after that initial effort of consistently learning N languages for 2*N years, the following languages become very easy to pick up. That's it :)
Really learning what you can safely ignore in whatever context is the most important part, everything past the basics is domain specific.
Having said that, I have read several language specifications which can be useful for general understanding. But, that’s simply the tip of the iceberg.
Anyway, I specifically mentioned knowing "some facts about the implementation" instead of "knowing the implementation inside-out". The same is true for tools, libraries, and frameworks - there is no need to remember every function/method signature and every class name in a library - as long as you know the most important parts and can quickly and accurately find the relevant documentation for the rest.
To me, 'knowing in depth' (as a language user) means that no matter the question, you know where to search for the answers. There's no need to remember the answers themselves, although it kind of happens naturally with repetition anyway.
On the other hand, it's also important to know which questions are not worth answering. It's exactly as you say:
> Really learning what you can safely ignore in whatever context is the most important part
So, to sum it up: if you can do both these things, then, to me, you have in-depth knowledge about the language (or actually any other field). The next step - ie. actually knowing all the answers by heart - is mostly useless for language users and only matters for (and is best left to) language implementers/advocates/nerds.
> A language like Java has a giant and evolving standard library plus multiple compilers etc. And that’s ignoring any simply popular libraries etc.
Java stdlib is only "huge" in comparison with C, where stdlib is non-existent. The popular libraries may be ported from other languages or even directly called via FFI. And if the library is really good, it will be ported to other languages, too, which means you'll have an easier time using these languages in the future.
Even without all that, though, if you know more-or-less what's where and can quickly search for the details - you're good. It's not that easy to learn this - you need to remember the structure of the docs at least - but it's much easier than actually learning and remembering all of the stdlib, etc.
For this reason I think it may be rational to only learn what will be used in the near future and spend the saved time on more timeless knowledge.
Like interpreter and compiler architectures, type systems kinds and their meaning, ways of specifying the semantics formally, and also the structure of novel kinds of abstractions proposed by researchers in some experimental languages.
If you learn all of that today, the next time you'd need to learn anything new about a mainstream PL would be in 10 years, if not twice that.
Example: many modern languages only recently started supporting some of the Algol-68 features. That's 50 years to get a lambda into the language...
It wasn't in academia, but I spent a while working on one of the major native front end platforms almost exclusively and had the opportunity to get very familiar with it. And by 'familiar' I don't mean just knowing where to look things up, I mean knowing many of the exact APIs by heart, and having a wide variety of things I could just type in (without much looking things up) even if it involved working with images, network requests, JSON, file IO, string processing, dates/scheduling, collections, serialization, menus, windows, controls, input, drawing, sound, etc.
Another big thing was when there are multiple ways do the same thing, having done it both ways and having direct experience of why one choice will likely be more effective in general or for a particular project. This can apply to choosing libraries/frameworks or app architectural decisions.
I noticed I missed this level of familiarity quite a lot when I switched to a different ecosystem later. Maybe this is worse for native UI development because of the large API surfaces. But I found needing to consult the documentation again to be a lot slower.
Having had that experience has kind of made me wonder about full-stack vs specialization, and optimal-language-for-the job vs standardizing (although of course some languages are totally inappropriate for some jobs). At least in my own experience I found sticking with the same language for a while to have continuing productivity benefits well beyond the 1 week/month period.
Core Data
SQLite
NSArchiver
NSKeyedArchiver
NSUserDefaults
JSON
Property lists
Protocol buffers
stdio
NSData
memory-mapped files
Realm
This is without getting into anything too obscure. This list is probably also out of date.
My claim was that:
> learning a new language - and yes, in-depth, including idioms, stdlib, some external libraries, maybe some framework (if needed), and also some facts about the implementation and its inner workings[1] - takes a week at most
I also tried to define "learning in-depth" in another post:
> To me, 'knowing in depth' (as a language user) means that no matter the question, you know where to [quickly] search for the answers. There's no need to remember the answers themselves, although it kind of happens naturally with repetition anyway.
> On the other hand, it's also important to know which questions are not worth answering. [ie. what to ignore while learning]
And I stand by it: I believe that there's no need to memorize too many details to be productive, you just need to be able to quickly and accurately find the relevant details, no matter which details are they. Various docs indexes and viewers, your IDE features, cheatsheets printed on a wall - all of that can help you if you forget a bit of syntax or a signature of a function. There's nothing, other than just reading a book or two, to help you if you don't understand a crucial concept in a language or the architecture of the library/framework.
Also, all these concepts are reused all over the place. For example: "Io is a purely-object-oriented language with prototypal inheritance which allows objects to have many parents." Each word here has a meaning, and that meaning is (well, mostly) standard across most programming languages. With this description, if you know all the words, you just learned 3/4 of all there is to Io OO. Another example: "Dylan is a purely-object-oriented language which is class-based, allows multiple inheritance, and also decouples methods from classes by relying on generic functions, which use multiple dispatch - similar to CLOS." This one is longer, but it's still a single sentence, which conveys most (or if you're familiar with CLOS - all) of the characteristics of Dylan's object system. Sure, there are obviously more features in Dylan that you need to know before you start coding... but they are all defined with a single sentence. It takes half an hour to go through them all, and - again, if you know the exact meaning of each word - at this point you know more about the language than a beginner programmer would learn in a year or two.
> I mean knowing many of the exact APIs by heart
I was like this in the past, so I know what you're talking about. Unfortunately, my epilepsy makes my memory reset significantly from time to time - I can't do it, or at least not for long. It caused a loss of productivity for a bit, but it went back up when I started using well-configured tools. This is why my definitions of "knowing in-depth" above are what they are - I live them, for better or worse.
> (without much looking things up) even if it involved working with images, network requests, JSON, file IO, string processing, dates/scheduling, collections, serialization, menus, windows, controls, input, drawing, sound, etc.
Yes, that's what tends to happen with repetition - unless your memory is impaired in some way - you just remember things. There's nothing else than repetition that can get you to that point, which also means you "only" need repetition to get there. In other words, it happens naturally with time, provided you consistently work with the given tech stack, and that you use it for the various things you mention.
But again: good tooling makes the rote memorization mostly unnecessary, and I really don't see many benefits of keeping all the idiosyncrasies of the whole stack in your head. It's completely different story if you code in Notepad without Internet access, though.
Further, all the things you mention are implemented in all general-purpose languages. Moreover, most implementations look really similar. In almost all languages "network requests" are built upon sockets - an OS-level mechanism. Images are more tricky because of decoding/encoding (which is handled almost everywhere by simply linking to libjpeg & co.), but after that they're 3-dimensional int array/vector/list/what-have-you (yes, there are other representations - and yes, they are all implemented across most PLs and have very similar characteristics everywhere). "file IO", too, is based upon OS-provided streams, or a crippled reimplementation thereof. It's the same everywhere. "collections" are almost language-agnostic: the names and interfaces may (slightly) differ, but the underlying data structures are the same everywhere. "input", "windows", "controls", "drawing" are event-based everywhere, and almost all languages have bindings to all the GUI frameworks. You can write GTK+ app in Python just as well as in OCaml or C# (even though GTK itself is C (I think?)) - and you'll get the same names and signatures, even.
You'll see for yourself in the decades to come - you're likely to switch the stack at least a few times by the time you retire. You'll see that most divisions in programming are illusions and - quite simply - matters of taste/personal preference, while in reality the differences between the popular languages, stacks, framework and systems are miniscule.
> Another big thing was when there are multiple ways do the same thing, having done it both ways and having direct experience of why one choice will likely be more effective in general or for a particular project. This can apply to choosing libraries/frameworks or app architectural decisions.
These are mostly language-neutral - the exact same considerations apply when deciding on library/framework or approach in every single language.
> I noticed I missed this level of familiarity quite a lot when I switched to a different ecosystem later. Maybe this is worse for native UI development because of the large API surfaces. But I found needing to consult the documentation again to be a lot slower.
It could be because of lack of proper helpers in your editor etc., but either way: if you stick with the new stack, you'll learn it naturally with time. You'll forget some of the previous stack (although I'm frequently surprised how I can recall specific quirks in technologies from 20 years ago.), which is also natural. Memory just seems to work this way. It'll take a few months to remember all the relevant details - less if the new tech is similar to something you already know.
Those sort of details I learned from extended use weren't really important for understanding things conceptually. But of course actually implementing something involves going through all the minor details and making lots of small choices. Being able to just breeze through that was really nice.
To use your example of a network request: on iOS it may be true the API is built on top of sockets or kqueue or whatever (I believe they've moved to user-space networking now but I don't really keep up). But you could use the toolkit APIs blocking on a background thread, or integrated with the main event loop with a delegate object, or on the event loop with a callback block. There's trade-offs to different ways of doing it (especially on a team project): some ways are more verbose, some introduce more thread-safety risk, using blocks everywhere may increase the chance that someone generates a memory leak through cyclic references, processing large requests could be more performant on older phones on a background thread, some patterns make it easy to cancel the request, etc.
I don't really miss iOS development. But I do miss the ability to go through all those details/trade-offs as quickly, and I kind of want stick with one thing long enough to develop that again.
Especially because as you observe many of the underlying concepts are the same anyway (especially among the popular languages that are the practical choices for most projects because of ecosystem/tooling concerns). To extend dxbydt's analogy I'd rather focus on the dish (problem-domain) than the cooking instruments.
That's obvious, although the "substantially" part is a bit vague. But it's still obviously true - you will be slower if you need to check the docs often, it's a given. But:
> I kind of want stick with one thing long enough to develop that again.
It should take just a few months at most. You'll get there much faster than you (I assume, sorry if I'm wrong) expect. :-)
Or is it that you're already many months after the switch, and you still feel that you're checking the docs very often and it slows you down? Maybe there's something wrong with the docs, then? Otherwise, you should probably try learning in a more structured manner, like reading a book or doing MOOC.
> But you could use the toolkit APIs blocking on a background thread, or integrated with the main event loop with a delegate object, or on the event loop with a callback block.
Exactly the same options are present in every general-purpose language. There are quirks, like Python and threading or JS and event-loop, but you get the choice of blocking/non-blocking, and later if the non-blocking is based on threads and synchronization or on an event loop (or coroutines, green threads, CSP, Actors, etc.) The only thing that changes is nomenclature, which for some reason language developers like to reinvent all the time.
> some ways are more verbose, some introduce more thread-safety risk, using blocks everywhere may increase the chance that someone generates a memory leak through cyclic references, processing large requests could be more performant on older phones on a background thread, some patterns make it easy to cancel the request, etc.
Ok, some of these are indeed specific to a given platform and have no direct equivalent in (as many) other languages and platforms.
Yes, you need to learn those - as there's no equivalent in other languages and stacks, you have no choice but to learn, no previous knowledge will help you with them.
However, these tend to be higher-level concerns, where understanding the concept is still more important than memorizing all the relevant details. You write: "some ways are more verbose", which is obviously true, but IMO it's more important here to understand what "verbosity" is, what trade-offs it presents, and what is the "correct" level of verbosity for the task. Knowing this, finding the solution with the right amount of verbosity is as simple as opening a bunch of libraries' GitHub pages and quickly glancing on the code examples there.
---
All in all, I'm not disagreeing with you at all. You're right that remembering a lot of details makes you faster. You're right that there are considerations unique to the stack of language.
What I'm saying is it's not hard to remember all the essential details: you only need spaced repetition, which happens naturally as you work. Further, while unique features for a lang or stack exist, they are very rare, and it's not hard to learn them (exactly because they're so different than the rest, which makes them stand out). All the other - non-unique - features and consideration form a large pool of concepts which are frequently reused across many (or most, depending on the feature) languages and stacks. Internalizing this pool of concepts lets you effortlessly switch stacks and languages; and while you're right that the productivity will drop after the switch, I assert that with a bit of effort it'll get back to normal levels after a short time - just a few months (for the real mastery it would take longer, of course, but that's true always and for every kind of work).
Anyway - thanks for the discussion, I enjoyed it very much, thank you. I hope it wasn't too boring on your side :-)
What about Rust's borrow checker? I considered it novel, but I'd love to find out it was stolen from somewhere.
[1] https://en.m.wikipedia.org/wiki/Clean_(programming_language)
Here's a challenge: come up with something that people generally think is fundamentally new. Given enough HN commenters, someone will present an example of how something super similar to that thing was already there 20-30 years prior.
In PL, there's a massive amount of awesome languages that pretty much existed for the purpose of writing a PhD or doing something funky with semantics. It takes /really really/ long to get into an industrial strength language. Look at Rust for example, it's the first incidence of real Algebraic types for a non-gc language (excluding C++), letting you do wonderful things like https://github.com/lloydmeta/frunk
Some of my favorites are
https://www.propellerheads.com/en/reason (i contend it's a fantastic programming language for the task)
But that was the point... :(
Or put another way, the major languages only include the "middle of the road", conservative features: mostly safe, uncontroversial, and well-specified and tested (it's all "mostly", "approximately" so, there are obvious exceptions). There is a limited supply of such features, which makes all the major languages have non-trivial amounts of overlap in terms of concepts or implementations. Moreover, even if one language implements a truly unique feature, it gets copied the next day (to where it makes sense), leading to even more similarity between languages.
The other part of what I'm saying is that if you research and learn as many unpopular languages as you can today - right now - you'll be covered (in terms of having to learn new features in your job's PL) for at least the next decade without any additional effort.
I thought that was exactly the point klibertp was making. The paragraph starts like this:
> Because there is very, very little unique features to each language. Unless you go to the fringes, you're bound to see the same concepts applied again and again and again
> try naming any "new" feature which was added to your favorite (EDIT: I meant mainstream - TIOBE top 10 or 20 - lang here!) language recently - and I'll show you that same feature implemented 10 or 20 years ago in another language(s).
This is a fun game and I'll answer for them on this one: OCaml (1996) has structural types.
That sounds like your "issue" isn't knowing too many languages but that you don't know any one language as in depth as they do though?
I don't see why you'd want to unlearn anything.. doesn't that knowledge only help?
I think there are benefits to learning more languages but also support the idea you should have at least one you're super comfortable with.. thats not mutually exclusive!
With only my own experience and that of people I’ve worked with to go by I can’t provide any broader scope, but I feel like it really is the case that a critical mass of familiarity with different languages and ecosystems makes it far easier to pick up and run with others and be more or less unaffected by the differences. It is probably important that the languages in your set be actually different though, rather than superficially different as most historically-popular languages have tended to be.
I suppose you don't _have_ to use different languages to learn new concepts, but it certainly helps in some cases. For example, learning about currying is going to be much more natural in F# than it would be in C#.
https://gist.github.com/prakhar1989/1b0a2c9849b2e1e912fb
“A wide variety of experiences might lead to well-roundedness, but not to greatness, nor even goodness.”
Not all academic code is that bad, but the heft is definitely towards that end of the pool.
I got really familiar with the distinction, because I spent a while translating PhD project/demo code into actual products for $JOB. It’s definitely mostly in making things secure, stable, maintainable, and debuggable that you lose most of the time.
Once the paper is written, the data analyzed, the project is done. There is no such thing as "maintainability" because the code isn't used past publication.
yk = C * xk + D * uk
is a lot clearer than
position_at_time_k = output_matrix * state_at_time_k + feedthrough_matrix * input_at_time_k.
The first is an idiom. The second is not.
But as a counterpoint, I only know what you meant by the first expression because I read the second expression.
I actually agree with you in large part, that short variable names can have more meaning within an established set of idioms because they allow you to parse whole statements at once. But there’s a trade-off involved, because mathematics can take symbology further than that’s useful.
For example:
E[i=0;5](i**2)
sum([i**2 for i in range(0,5)])
So it often comes down to a matter of taste. position = C * state + D * input
Reasoning: k is the only subscript, so it can be dropped. Meaning of C and D are implicitly defined through their function wrt to state and input, so its OK not to name them. It also keeps the structure visible similar to that of the math.As a developer you are the chef. If all you can make is spaghetti, is it the kitchen's fault? OP makes the point explicit: the language shapes the way you approach problem solving.
When declarative, functional and procedural programming all yield the "same fucking spaghetti", you might just have missed the point.
Maybe because I'm also unfamiliar with it, I can't judge. But knowing the right set of algorithms to solve domain specific problem sounds language agnostic to me.
That said, I agree that you should also continue to learn about CS, learn more data-structures, more algorithms, explore newer techniques and paradigms. That includes learning new languages, but not only that.
It sounds to me like you're working in a highly specialized area that requires deep domain knowledge and rich set of tools to apply that knowledge. Your colleagues have a lot of familiarity with that domain and those tools. Knowing multiple languages isn't your problem, it's just that you haven't spent your entire career working in this particular domain and you're playing catch-up.
VB6 Kix scripts Powershell .net 3.5 Winforms WPF .net 4+ .net core .net asp Java JavaScript React Angular C++ Golang.
If programming is a job and not your craft, it will be harder for you. You just have to practice more.
That just sounds like some mess that one is forced to deal with, not reasonable software engineering. I mean yes, some jobs will drown one in useless stuff. Doesn't mean that learning the useless stuff is a virtue now.
So, TBH, my gut reaction to your comment is you might lack experience developing & shipping any large applications. That’s not an insult, and not a judgement; experience comes with time. Plus I don’t know your experience, I’m just letting you know what your comment leads me to assume. My only suggestion is to be a bit careful throwing around judgmental words like mess and useless and ‘not reasonable’ when you don’t know precisely what you’re talking about.
FWIW, this stack looks very normal even for a web-only application, and it looks simpler to me than the stacks & tech people use for shipping console games. Hell, I’ve written personal projects with tech stacks that have as many pieces.
If I’m off the mark about your experience level, you could make your case stronger by demonstrating that there’s a simpler cleaner alternative that solves the same problems, provides the same or better performance, build utility, maintainability, deployment, user experience, etc.. Do you have any suggestions?
This is what happens when one gobbles up whatever Microsoft throws over the fence... and it's clear they haven't learned their lesson because .NET core is on the list. There is no simpler, cleaner, alternative for them. By their nature such companies will (almost?) always end up in this situation.
Any developer working for them must now learn VB6, ASP.NET and Powershell and other great future-proof tech. That is, once again, not a great career move and certainly not an argument for learning many languages.
For the sake of discussion, that entire stack could probably have been kept to C++, Java, HTML5 and something for scripting assuming a talented engineering team.
C++ would have covered their Windows desktop needs from Windows 9x until today, including going cross-platform if needed.
Java would have covered cross-platform desktop apps and back-end, likely including whatever they're using golang for. Had they wanted more agility on the BE they could have gone with Python which doubles as scripting language.
HTML5 is self-explanatory. No need for fancy schmancy React or Angular which I bet they'll have to replace (or rather append to) in 5 years time.
It's only small and well-defined software that can get away in being written in one technology. For anything larger/serious, you're bound to end up in a polyglot environment.
Yes, most environments use several programming languages. Done right, this can be Google's blessed languages approach. Done wrong, it can be every technology Microsoft ever brought into existence, ending up with a triplicate solution for each problem.
which language is this? I'm guessing Python.
ofcourse, when I was a wageslave in the bay area, its nice to know python, java, javascript, scala etc. - got me jobs every 2-3 years & put food on table.
now that i'm in academia, its completely upside down. literally everybody is way more productive than me in just about any task. The other day I as supposed to program a poisson clock, it took forever. Meanwhile my advisors & classmates with zero industry experience chug thru these tasks effortlessly. Lately I've confirmed its because they know exactly 1 language , but they know it so well & in so much depth, they know exactly where to look, the right mcmc library, the right slice sampler, the right optimizer, that's what matters.
There's no point programming the same bloody front-end & back-end in a dozen different languages just because of industry constraints. That's like eating a spaghetti with a fork, a spoon, with chopsticks, with your fingers...its the same fucking spaghetti. cook something else, not just rotate dish-ware.