7 ms·
Different languages also have their own culture and ecosystem, which are also valuable to learn in order to get a different perspective. Some things that are t
by synthc 4y ago
Different languages also have their own culture and ecosystem, which are also valuable to learn in order to get a different perspective.
Some things that are taken as best practices are bad practices in other langauges and vice versa.
For example, lots of Java devs are against early and multiple returns to the point of absurdity, while in functional languages this is idiomatic and no problem at all.
Using different languages lets you see how different approaches work out in practice, so you can get a better view about which approaches work and which approaches are just cargo-cult nonsense.
- sendomatic 4y agoI find the java example different to my experience. java doesn't have all expressions return values, like if, making the attempt to have single returns from functions much harder to do tidily than in other languages like for example ruby, rust, scala.
- 0x445442 4y agoYou can program just about any darned way in Java which can lead to some pretty schizophrenic code bases and organizations. I recall a fairly recent code review where the author had a static method in a class which took in another type, did some reasoning on the state of the type and returned a result. I asked why that method was not in the type itself since all the state required to answer the question lived in the instance of that object. The author said, oh we tend not to use “smart” objects.
- BlargMcLarg 4y agoThe problem being, cargocults tend to hold the power. So yes, learn new concepts, practice them and more, but don't be surprised if in practice you can barely utilize them thanks to cargocults insisting they are wrong. We see this in C#. Has a ridiculous amount of features outside default OOP and continues to get more baseline, even has great interop with several other languages. But culture changes very, very slowly. Large scale adoption tends to happen only when some major framework insists on using a certain paradigm.
- tester756 4y agoWhich features are you talking about?
- BlargMcLarg 4y agoTake about anything you like of minimum level C# 6. My personal gripe being poor adoption of tuples/anonymous types and records. C# has been trending towards introducing more things from the functional paradigm in particular, but just getting away from typical OOP patterns and replacing them with something more on the spot or functional isn't amazingly well received. The main thing which seems very well adopted is LINQ, and that's primarily due to Entity Framework and Microsoft pushing LINQ-adoption hard. Most places still program in C# as if it were Java with Lombok built-in. And that's where I'm getting at mostly. New paradigms and languages are cool, but historically it's been difficult for them to get mass adoption unless a big name is pushing for it hard. Convergence has been the name of the game for a while now, rather than divergence.
- cplusplusfellow 4y agoThe reason why I’m not adopting C# is because I’m never going to be a windows user.
- hardware2win 4y agoIt works on Linux just fine
- ok123456 4y agoProblem is the mono C# compiler is several years behind Roslyn in terms of features. It's pretty much a non-starter if you don't have nullable types in 2022.
- Jtsummers 4y agohttps://dotnet.microsoft.com/en-us/download https://dotnet.microsoft.com/en-us/download Works fine on non-Windows systems (well, Linux and macOS at least) IME and isn't several years behind.
- rantingdemon 4y agoI think this is my first post on HN, but have been a long time lurker. That aside. Your point around ecosystems is interesting to me. As a wannabee coder I'm always trying new things. Most of my code was in PowerShell although I did do a bit of C++ and Delphi in school. I have been dabbling with dotnet core (C#) and Python the last couple of years. I tried to get into Java a bit, but to be frank the learning curve to go from start to consuming a REST service was just way too hard. I couldn't understand the difference between when I should be using JavaEE, JavaSE, spring boot, spring framework etc. I gave up after two days. In contrast Python is just so easy. And if I want something more robust I'll rather go to dotnet. Go is on my list as it seems to offer a lot of what I want, and although there are some apparently weird things in it I think i can be productive with it for some basic business logic within a couple of days.
- syzygyhack 4y agoYou sound like you'd enjoy TypeScript with NodeJS. Low learning curve. Highly productive. Massively versatile ecosystem. You can be functional or OO. And of course, the type system, which will feel similar to C#. It's very fast and obviously JS being the language of the web is a natural benefit too.
- FractalHQ 4y agoThis is the way. Being able to make a website, PWA, cross-platform desktop app with Tauri, mobile app with RN / Quasar / Svelte Native / Cordova, or a standalone cross-platform executable with Deno is invaluable. Edge functions / cloudflare workers / Deno deploy, or even embedded js runtimes are all first class. As a typescript dev I feel like I can do almost anything, and UI is cake with Svelte and the other great web ui frameworks around JS. Not to mention the incredible ecosystem and the top-tier DX with PNPM and Vite. I feel spoiled when the possibilities are limitless and the tooling / ecosystem has it all!
- eyelidlessness 4y agoFor starting with TypeScript today, I’d almost certainly recommend trying Deno before Node. It’s much closer to standard web APIs, the tooling story is “you don’t need any until you know you do”. And it doesn’t have a zillion footguns like CJS/ESM interop, or different stream APIs, or complex package.json configs.
- eweise 4y ago"For example, lots of Java devs are against early and multiple returns to the point of absurdity, while in functional languages this is idiomatic and no problem at all." Which functional language are you talking about? Of the two functional languages I know, Elm can only have a single return statement. Scala encourages a single return.
- mrighele 4y agoIn a functional language technically you don’t have multiple returns, because the function is a single expression so in a way you’re right. On the other hand the actual result of the expression is determined on a leaf of the expression so you could consider it a return point To make an example the following expression can be considered to have two returns: max x y = if x > y then x else y The Java equivalent is int max(int x,int y) { if (x>y) return x; else return y; } Some people abhor the idea of having multiple returns in a method, and say that you should write it like int max(int x, int y) { int result; if (x>y) result = x; else result = y; return result; } (Disclaimer: Contrived and buggy example as I am on mobile)
- synthc 4y agoYes this is exactly what I meant. After years of coding in Haskell and Clojure, and then going back to Java I have absolutely no problems with int max(int x,int y) { if (x>y) return x; else return y; } I just looks completely fine to me, but colleagues would complain about it in reviews and I just don't understant the problem at all. The variant with the extra result variable looks just wierd to me, and I have seen much uglier code written by people desperately avoiding early/multiple returns.
- saltcured 4y agoWhat do these languages do when you accidentally miss a branch in you decision tree? Is there any lexical or static analysis error, or does it cause a runtime error or implicit null return when you hit the actual missed condition? I think these differences in potential outcomes are what guide many of these cultural rules of thumb in different programming styles. In imperative programming, a bunch of nested conditionals can easily have incomplete coverage of possible program states, and it can be easy to overlook problems if you have a mixture of side-effect branches and early returns. I think some people struggle with this more than others, and it can flummox them almost like goto-laden spaghetti code. Of course, there are other areas where similar errors can occur in different languages, i.e. in exception-handling or pattern-matching constructs. There are many different coding styles which can make these control-flow structures easier or harder to debug. But, I think there can also be a lot of "cargo culting" where zombie rules of thumb continue beyond when they were really particularly helpful.
- iudqnolq 4y agoRust convinced me that having a section at the top of a function that early returns in error/exceptional situations works very well. I find myself missing this in the one functional language I've tried, Elixir, although I find Elixir worth it for other reasons. I initially fell in love with the Rust convention of simply bubbling up errors throughout a function but I've gradually realized that leads to a poor API. [1] I'm currently learning c++ for a personal project. I want to use a library with an API that's sufficiently templated it'll be easier to write a c++ shim than directly generating bindings. So far I'm at the stage where I'm constantly thinking Rust does things better. Hopefully later on I'll realize why the different tradeoffs c++ makes make sense. (One example would be how generic code is typechecked). [1]: If you want to be able to simply propagate up errors with the `?` operator you need to implement automatic conversations from your dependencies' errors to your error type. But that means your API will have a single error type for every dependency error type - say MyError::Io(io::Error) - which is the wrong level of specificity. I now think you should either expose only a string message your user can just show their end user or an error that's much more specific so they can write code that intelligently responds to it. Something like MyError::ReadConfigFailed(io::Error)
- chaorace 4y agoRegarding citation #1: I'm a Rust learner myself, so this is something that's rather salient for me. What do you think about the "boxing errors[1]" approach? This strikes me as one possible way you could bubble up dependency errors without being forced to deal with type conversions. [1]: https://doc.rust-lang.org/rust-by-example/error/multiple_error_types/boxing_errors.html https://doc.rust-lang.org/rust-by-example/error/multiple_err...
- iudqnolq 4y agoWhen I said > I now think you should either expose only a string message your user can just show their end user or an error that's much more specific so they can write code that intelligently responds to it. a boxed trait object is the main way to implement an error that merely conveys a string message.