Important not to mistake fluency for favourite. I code mostly in python but I am attracted to lisp and Haskell.
Because they have beautiful simplicity in the first case and interesting outcomes in the second. I continue to struggle to achieve expressiveness in either. Maybe before I die.
But my real favourite is awk. Because it was the first language I used with a hash structure and so let me explore writing code which did content addressed things like count uniques over stdin string streams from logs. All kinds of languages had functions and procedures and fancy schmancy if then else but having dynamically sized data which indexed off data.. that was electrifying. Perl had them after and I suspect that in part accounted for it's popularity. Every scripting language since has too.
There is this oddness between how programming in Haskell feels and programming in Python. Each time I go back to Haskell to try and learn a bit more about that environment, I find the mindset carrying over to what I write in Python.
I spent a few years as a Python developer followed by a few years working with Haskell. Now I've gone back to Python and I'm a much better Python developer because of my Haskell experience. In fact I think I'm even better than I would have been if I'd swapped my Haskell time for more Python time.
Let me earn myself a -4. I do my hobby code in VB .NET. VB6 was the first thing I learned, and whether I'm doing C++, C#, or PHP, whatever else I've ever used, I'm usually translating in my head what I want to do... from VB.
So I've ended up back at VB after several years in other languages because it cuts out the cognitive load.
Probably javascript. With the caveat that all of the work I've done in javascript has been of the old school "write it in a text editor and FTP it to the server" variety, and I have little real exposure to the modern ecosystem or the problems people seem to have with javascript at scale.
I like the simplicity of the syntax. Arrays and objects are easy, closures are easy, and I like prototypal inheritance as a concept, although you're not supposed to actually use it in practice.
Lua is probably a close second, though. If I were to design a programming language, it would probably be somewhere between the two, with some C++ features tossed in for flavor (operator and function overloading, maybe generics.)
I second this. I love ES5. It was a beautiful, simple language. And it runs just the same on literally every device.
The JavaScript community has taken a horrible turn towards complexity. I’ve been planning a fork of the npm tree, to return to ES5. But it’s a big project and I want to be ready with a good modern, modular web toolkit before I do.
(The plan is not just to fork an ES5-compatible tree, but to allow people to rewind the npm tree to an arbitrary branch mask based on any linting rule they like and append from there. If you want to narrow to only typescript+react packages with named exports for tree shaking, you could. I’m gonna do good old fashioned ES5 though, no promises allowed and no assignment in global scope)
i understand your love for javascript... but i dont understand the hate for es6 & upwards. ive rewritten all my code to atleast es2015 and lost so much overhead while doing it wich makes my projects alot easier to maintain. (and alot more predictable)
the only thing wich is lacking right now is native support for it in the browsers
Promises introduce declarative control structures basically between every function call in an async application, which is a nightmare for debugging.
ES6 introduces way more syntax, making it much harder for beginners to learn.
Arrow functions make scope much harder to reason about, which makes closures more of an anti-pattern. In ES6 closures are one of a tiny number of scope patterns so you can actually use them.
Arrow functions cause bind to break in unpredictable ways.
Most other ES6 features are just syntactic sugar which offer no software engineering benefit and add a whole layer of conflicting code styles that one must constantly switch between, or else deal with constant pointless linting fixes if you are adhering to a consistent standard.
ES6 demands you use a transpiler which makes debugging flakier, and adds another place for bugs and maintenance work, in addition to often slowing he build down.
If I wanted deal with that much headache I’d just use typescript and at least get type checking in exchange for the syntax change and transpile step.
ES6 exists because some programmers never understood prototype and bind. And felt naming a function that is only called once was icky. Mostly former Ruby programmers. So they bolted a shitty Ruby onto JavaScript in order to get people to stop using prototype and bind, which are the heart of JavaScript’s control flow.
I think I subconsciously fell in love with Python because of something a bit silly... the bias towards keywords over symbols.
I think there's some pattern recognition routine in my head that convinces itself we're reading prose, based on the ratio of words to symbols, so it feels comfortable for a amateur hobbyist like me.
I know "bias towards keywords" isn't a functional language feature, but I think it is a nice UX.
Of course, then I learned about generators and decorators in Python... Those are fun too.
"Thinking in Python" is a thing -- kinda. It's like "thinking in Lisp" or "thinking in Haskel." Each of these makes you a better programmer, in my opinion!
Python. Just because of the community. There are amazing developers involved in every bit of the Python community, from machine learning libraries to web frameworks :)
It's hard to find a problem that only has one Python library that solves it. Most of the time you have a dozen, and half of those are maintained better than I'd ever expect.
I have been meaning to try datomic for a while but love every minute of my current job doing Clojure. My company has been converting everything to it at every reasonable time, from web servers to massive ETL jobs to our Clojurescript React Native mobile apps. We've always been very happy with the conciseness of the code, the clarity gained from immutability and pure functions, the performance switching off Rails to the JVM and far easier parallel programming tools, and the ability to utilize the vast Java/JavaScript ecosystem if someone hasn't written something in Clojure itself. No ecosystem is perfect, but it has been the most charming environment I've worked with ever. Cursive rocks too!
Okay, okay... I’ll be the lone Swift user. I really enjoy the type safety and in line parameter names on function calls. Of the type safe languages it feels like it has the minimal about of scaffolding needed to run some code.
Haskell. I like the power of using a powerful type system to get more guarantees when you compile your program. It's like getting additional unit tests with 100% code coverage for free.
Python. I'm an "infrequent" programmer, and I find the syntax sticks with me between projects, which is a huge time-saver. It's also the cleanest, most readable language I've ever programmed in, though I realize that's an extremely personal preference. Like brownbat, I have a bias for keywords over symbols. I'm also a huge fan of "explicit over implicit" and "there should be one right way to do it," which is why I favor Python over Ruby. The biggest win, though, as I've gotten more experienced with the language, is the ease and simplicity of "pythonic" programming--using iterators, generators and list comprehensions, favoring built-in data types (dictionaries, tuples and sets) over custom classes, and so on. My Python programs tend to be much, much shorter than what I'd write in C++ or C#, easier to read and quicker to write. Win, win, win for my purposes as I mostly don't care about speed ...
Julia lover here. I love having math at my fingertips and the ease of writing x’x\x’y. I like writing numerical code, knowing I can change types later and it will likely work. Still, I miss tab-tab from ipython for method completion from time to time and I work all day in mostly C++.
Kotlin. Less verbose than java, functional and modern features when I want them but doesn't implement every programming idea like scala. My second favorite language is python, but I like getting the type safety while writing way less code.
Another vote for Kotlin - it strikes just the right balances for me in the functional vs. objective and verbosity vs. readability ranges.
Its connection to Java brings a huge ecosystem of tools and libraries to the table, but if you don't need those, today Kotlin can also be used without Java or the JVM.
It has been my main language for work projects for over a year now and I still love the language.
swift, because it has a high level syntax with a really nice Generics implementation, but can still interface relatively easily with low level API's. Also because it uses reference counting for memory management instead of mark and sweep garbage collection so has more predictable performance and low memory overhead.
C# is my favorite language as long as we're only talking about the language. It gets out of my way - I can write it without thinking consciously about the programming language. If the run-time didn't have garbage collection, it would be my ideal language. The GC never gets out of my way, ever.
At the moment, Go. I like the focus on features that make programmers happy, like `gofmt`. I love that most of the things I want to be able to do are already available as a library - it feels like Python in that regard. I really love how easy it is to cross compile for different platforms. I think they still have some issues with dependency management, but `dep` has made my life much better already.
I love Rust as well, though I love it more as a concept than as an actual useful language. If only it weren't so freaking hard to get anything done in that language!
Racket: it has the feeling of having been constructed by people much smarter than me, who are eager to help me get smarter myself. The docs and guide are a joy.
Python is my favourite by far, mainly because when I first read over the syntax I typed in an ultra simple program and it worked first time. Normally, you would wrestle with constructors, imports / includes and semi colons in the appropriate places, but the fact that this program worked first time really impressed me.
It has a beautiful clean syntax, which is as concise as I can imagine that a human readable language could get to giving instructions to a computer.
My favorite programming language is Zero (yes it is my invention). If you have not heard of it then I am not surprised because the language is very new (theoretical actually). You develop programs in it by defining new infinite sequences from existing ones.
All begins with the primitive infinite sequences and the language's means of combination (specified with decimal digits)
---universe begin---
sequence 01: 0 1 2 3 4 5 ...
sequence 03: 1 2 3 4 5 6 ...
sequence 05: 2 3 4 5 6 7 ...
sequence 07: 3 4 5 6 7 8 ...
...
---universe end---
0105: count by two
---universe begin---
sequence 01: 0 1 2 3 4 5 ...
sequence 02: 0 2 4 6 8 10...
sequence 03: 1 2 3 4 5 6 ...
sequence 05: 2 3 4 5 6 7 ...
sequence 06: 1 3 5 7 9 11 ...
sequence 07: 3 4 5 6 7 8 ...
...
---universe end---
01030501: set up some cycles
---universe begin---
sequence 01: 0 1 2 3 4 5 ...
sequence 02: 0 2 4 6 8 10...
sequence 03: 1 2 3 4 5 6 ...
sequence 04: 0 1 2 0 1 2 ...
sequence 05: 2 3 4 5 6 7 ...
sequence 06: 1 3 5 7 9 11 ...
sequence 07: 3 4 5 6 7 8 ...
...
---universe end---
Please note that as the universe grows we always leave space for more sequences by skipping every other sequence designation.
What makes this language useful is that with very little effort any two arbitrary infinite sequences can be defined. As a consequence any mathematical relation is easily defined as a mapping from members of one sequence to the corresponding members of the other sequence.
I will briefly describe the language's means of combination. Writing a sequence designation one next to another will form new sequences by pulling out corresponding members. But all sequences are infinite so after the last designated sequence is visited the member value is used to select the possibly new member in the first designated sequence. Digits that are not able to be confused with sequence designations specify the three other primary means of combination. They are "cons", "car", "cdr". With a proper understanding of their use one can build arbitrary sequences. I will just say that "cons", "car", and "cdr" are used to combine entire sequences which is logically equivalent to combining corresponding members of those sequences.
In the code above I write "0105". The "01" is a sequence designation. The "05" is a sequence designation.
I define an infinite number of new sequences twice over in the example above. Between "---universe begin---" and "---universe end---" is listed the state of the universe. After inspecting the current state of the universe one can add new sequences with numeric codes as I have attempted to describe. The example above shows two iterations of this process. In each case an infinite number of sequences is added. So really your program will describe an infinite sequence of infinite sequences. And, if you never stop programming, then you are actively directing an infinite sequence of infinite sequences of infinite sequences!
The purpose of the language is to be "general purpose". Any programming problem can be modeled with this language. Because a number represents anything atall, I would not hesitate to use the language anywhere I have need for an algorithm. Input transformed to number is manipulated by algorithm then presented to the user as output. A gui is typically used to control this process.
Impressively, it is possible to write relations with very little knowledge of specific algorithms. For instance, you may know how to square a number but be totally ignorant of methods to find the inverse function (the square root). Not a problem - you already know enough to direct the computer to take square roots. This might seem magical. It certainly is magnificent, but there is no magic involved. It all has to do with the design of the language.
I might have said Haskell, except I have very little hands on experience with Haskell.
Elm is such a joy. Here are some reasons!
1. In the end, all your code is either functions or data!
2. There are only a few core concepts, and very little extra language features. There is zero implicit indirection. (E.g. macros or class inheritance.) As a result, it’s incredibly easy to reason about what the code is doing.
3. It’s incredibly straightforward to reason about what code is doing. Function bodies are just a single expression saying what the function returns. Functions are 100% “pure”; they don’t perform side effects, and when you pass in the same input you always always get the same output.
I work in Elixir day-to-day. Elixir’s great, but just today I spent hours digging through internals of Phoenix (the prevailing web framework) to implement a “low level” abstraction in our application. Trying to understand the flow of code in Phoenix was painful! (Because a lot of advanced language features are used that bring more layers of indirection.) Not so in Elm. There’s no objects, no classes, no inheritance hierarchies. Everything is way more concrete and clear from the get go.
For fun, Scheme/Lisp. Once you have macros it really feels like the sky is the limit in terms of what you can express.
I've also been liking Go quite a bit recently. I know it's a language HN loves to hate. It's not as expressive as some other languages. But I feel like creativity within constraints can also be rewarding (kind of like writing a haiku). If I can find a way to reformulate my problem so that it can be expressed easily in Go, I'm often happy with the result. And because the abstractions Go provides are not very costly, it usually executes efficiently too.
It's hard to find a language that combines high level features with the lower level features that performance-sensitive apps often need (like value types, control of memory layout, etc). Also GC simplifies a lot of things, and Go makes it practical for a wider class of applications with sub-ms pauses and making it easy to minimize allocations. C++/Rust involve more programmer effort around ownership, and C# can also involve more programmer effort since minimizing allocations is trickier and GC impact is greater. It's not a big language but the combination of features / trade offs seems really practical.
Go's also widely used enough where you don't need to worry about having a robust library if you need HTTP2 or something.
59 comments
[ 2.9 ms ] story [ 115 ms ] threadBecause they have beautiful simplicity in the first case and interesting outcomes in the second. I continue to struggle to achieve expressiveness in either. Maybe before I die.
But my real favourite is awk. Because it was the first language I used with a hash structure and so let me explore writing code which did content addressed things like count uniques over stdin string streams from logs. All kinds of languages had functions and procedures and fancy schmancy if then else but having dynamically sized data which indexed off data.. that was electrifying. Perl had them after and I suspect that in part accounted for it's popularity. Every scripting language since has too.
Thinking in yield() generators goes naturally to composition of functions. That's about my limit.
So I've ended up back at VB after several years in other languages because it cuts out the cognitive load.
I like the simplicity of the syntax. Arrays and objects are easy, closures are easy, and I like prototypal inheritance as a concept, although you're not supposed to actually use it in practice.
Lua is probably a close second, though. If I were to design a programming language, it would probably be somewhere between the two, with some C++ features tossed in for flavor (operator and function overloading, maybe generics.)
The JavaScript community has taken a horrible turn towards complexity. I’ve been planning a fork of the npm tree, to return to ES5. But it’s a big project and I want to be ready with a good modern, modular web toolkit before I do.
(The plan is not just to fork an ES5-compatible tree, but to allow people to rewind the npm tree to an arbitrary branch mask based on any linting rule they like and append from there. If you want to narrow to only typescript+react packages with named exports for tree shaking, you could. I’m gonna do good old fashioned ES5 though, no promises allowed and no assignment in global scope)
the only thing wich is lacking right now is native support for it in the browsers
ES6 introduces way more syntax, making it much harder for beginners to learn.
Arrow functions make scope much harder to reason about, which makes closures more of an anti-pattern. In ES6 closures are one of a tiny number of scope patterns so you can actually use them.
Arrow functions cause bind to break in unpredictable ways.
Most other ES6 features are just syntactic sugar which offer no software engineering benefit and add a whole layer of conflicting code styles that one must constantly switch between, or else deal with constant pointless linting fixes if you are adhering to a consistent standard.
ES6 demands you use a transpiler which makes debugging flakier, and adds another place for bugs and maintenance work, in addition to often slowing he build down.
If I wanted deal with that much headache I’d just use typescript and at least get type checking in exchange for the syntax change and transpile step.
ES6 exists because some programmers never understood prototype and bind. And felt naming a function that is only called once was icky. Mostly former Ruby programmers. So they bolted a shitty Ruby onto JavaScript in order to get people to stop using prototype and bind, which are the heart of JavaScript’s control flow.
Basically the chest burster from Alien.
I think there's some pattern recognition routine in my head that convinces itself we're reading prose, based on the ratio of words to symbols, so it feels comfortable for a amateur hobbyist like me.
I know "bias towards keywords" isn't a functional language feature, but I think it is a nice UX.
Of course, then I learned about generators and decorators in Python... Those are fun too.
Generators are certainly "thinking in Python."
It's hard to find a problem that only has one Python library that solves it. Most of the time you have a dozen, and half of those are maintained better than I'd ever expect.
Its connection to Java brings a huge ecosystem of tools and libraries to the table, but if you don't need those, today Kotlin can also be used without Java or the JVM.
It has been my main language for work projects for over a year now and I still love the language.
I love Rust as well, though I love it more as a concept than as an actual useful language. If only it weren't so freaking hard to get anything done in that language!
I find Haskell clears up your thinking a lot, but it's really not great for production work. Go on the other hand is extremely great for prod work
It has a beautiful clean syntax, which is as concise as I can imagine that a human readable language could get to giving instructions to a computer.
All begins with the primitive infinite sequences and the language's means of combination (specified with decimal digits)
---universe begin---
sequence 01: 0 1 2 3 4 5 ...
sequence 03: 1 2 3 4 5 6 ...
sequence 05: 2 3 4 5 6 7 ...
sequence 07: 3 4 5 6 7 8 ...
...
---universe end---
0105: count by two
---universe begin---
sequence 01: 0 1 2 3 4 5 ...
sequence 02: 0 2 4 6 8 10...
sequence 03: 1 2 3 4 5 6 ...
sequence 05: 2 3 4 5 6 7 ...
sequence 06: 1 3 5 7 9 11 ...
sequence 07: 3 4 5 6 7 8 ...
...
---universe end---
01030501: set up some cycles
---universe begin---
sequence 01: 0 1 2 3 4 5 ...
sequence 02: 0 2 4 6 8 10...
sequence 03: 1 2 3 4 5 6 ...
sequence 04: 0 1 2 0 1 2 ...
sequence 05: 2 3 4 5 6 7 ...
sequence 06: 1 3 5 7 9 11 ...
sequence 07: 3 4 5 6 7 8 ...
...
---universe end---
Please note that as the universe grows we always leave space for more sequences by skipping every other sequence designation.
What makes this language useful is that with very little effort any two arbitrary infinite sequences can be defined. As a consequence any mathematical relation is easily defined as a mapping from members of one sequence to the corresponding members of the other sequence.
I will briefly describe the language's means of combination. Writing a sequence designation one next to another will form new sequences by pulling out corresponding members. But all sequences are infinite so after the last designated sequence is visited the member value is used to select the possibly new member in the first designated sequence. Digits that are not able to be confused with sequence designations specify the three other primary means of combination. They are "cons", "car", "cdr". With a proper understanding of their use one can build arbitrary sequences. I will just say that "cons", "car", and "cdr" are used to combine entire sequences which is logically equivalent to combining corresponding members of those sequences.
In the code above I write "0105". The "01" is a sequence designation. The "05" is a sequence designation.
I define an infinite number of new sequences twice over in the example above. Between "---universe begin---" and "---universe end---" is listed the state of the universe. After inspecting the current state of the universe one can add new sequences with numeric codes as I have attempted to describe. The example above shows two iterations of this process. In each case an infinite number of sequences is added. So really your program will describe an infinite sequence of infinite sequences. And, if you never stop programming, then you are actively directing an infinite sequence of infinite sequences of infinite sequences!
The purpose of the language is to be "general purpose". Any programming problem can be modeled with this language. Because a number represents anything at all, I would not hesitate to use the language anywhere I have need for an algorithm. Input transformed to number is manipulated by algorithm then presented to the user as output. A gui is typically used to control this process.
Impressively, it is possible to write relations with very little knowledge of specific algorithms. For instance, you may know how to square a number but be totally ignorant of methods to find the inverse function (the square root). Not a problem - you already know enough to direct the computer to take square roots. This might seem magical. It certainly is magnificent, but there is no magic involved. It all has to do with the design of the language.
I might have said Haskell, except I have very little hands on experience with Haskell.
Elm is such a joy. Here are some reasons!
1. In the end, all your code is either functions or data!
2. There are only a few core concepts, and very little extra language features. There is zero implicit indirection. (E.g. macros or class inheritance.) As a result, it’s incredibly easy to reason about what the code is doing.
3. It’s incredibly straightforward to reason about what code is doing. Function bodies are just a single expression saying what the function returns. Functions are 100% “pure”; they don’t perform side effects, and when you pass in the same input you always always get the same output.
I work in Elixir day-to-day. Elixir’s great, but just today I spent hours digging through internals of Phoenix (the prevailing web framework) to implement a “low level” abstraction in our application. Trying to understand the flow of code in Phoenix was painful! (Because a lot of advanced language features are used that bring more layers of indirection.) Not so in Elm. There’s no objects, no classes, no inheritance hierarchies. Everything is way more concrete and clear from the get go.
are there any cases where elm was not the ideal solution but js was?
I'm still amazed how much stuff is build in and don't need a plug-in or extension or need you to write your own function...
I've also been liking Go quite a bit recently. I know it's a language HN loves to hate. It's not as expressive as some other languages. But I feel like creativity within constraints can also be rewarding (kind of like writing a haiku). If I can find a way to reformulate my problem so that it can be expressed easily in Go, I'm often happy with the result. And because the abstractions Go provides are not very costly, it usually executes efficiently too.
It's hard to find a language that combines high level features with the lower level features that performance-sensitive apps often need (like value types, control of memory layout, etc). Also GC simplifies a lot of things, and Go makes it practical for a wider class of applications with sub-ms pauses and making it easy to minimize allocations. C++/Rust involve more programmer effort around ownership, and C# can also involve more programmer effort since minimizing allocations is trickier and GC impact is greater. It's not a big language but the combination of features / trade offs seems really practical.
Go's also widely used enough where you don't need to worry about having a robust library if you need HTTP2 or something.