7 ms·
Writing Java in my day job currently, I really miss C#. It feels slightly more like a "Java done right" -- the same strategy of bringing "fancier" features from
by __float 5y ago
Writing Java in my day job currently, I really miss C#. It feels slightly more like a "Java done right" -- the same strategy of bringing "fancier" features from F# or other languages, but it has just a _few_ more features that make day to day development just a little more pleasant.
- kaba0 5y agoNah, C# has a shitton of more features, some of them indeed making the day to day development more pleasant, while the other ones are known only by a handful of people, has strange interoperability with everything else or is superseded already by another one. It is really on the way to become as complex as C++ is.
- tkot 5y agoCould you list these features? I was under the impression that apart from some things that can be easily done in C# but are pretty much impossible to do in Java (like value types* and pointers) the languages were pretty similar. Some C# things seemed rather strange (like delegates), some purely cosmetic (like indexers) and there were also things that Java had but C# did not like covariant return types (available from C# 9.0) *Project Valhalla is supposed to bring it to Java but I wouldn't hold my breath waiting for it.
- lou1306 5y agoAccessors come to mind: class Foo { int Bar { get; set } } Allow you to get/set the value of someFoo.Bar as if it were a public member. If you want read- or write-only members, you just remove the "set" or "get" portion. If at some point you need to add logic to the setter, you just do int Bar { get; set { /* setter logic goes here */ } } You still use assignment syntax ("someFoo.Bar = newValue"), but this syntax is desugared into a call to the setter method. Ditto for the getter. IMHO they make class APIs much cleaner and forward-compatible (on the other hand, if you started with a public member and then need to add a proper setter with some logic, you would break the API). Also, non-nullable types are a pretty nice way to avoid checking for null every other line of code. And these are literally just the first couple examples that came to mind.
- pulse7 5y agoIf you need a shortcut for accessors, you may aswell make your fields public and avoid get/set altogether...
- pivo 5y agoNot if you need to implement some setter logic though, or want to reserve the option to do so in the future. And not if you want those instance variables to be available as JavaBean properties. I haven't developed in Java in a long time, but public instance variables were a no-no when I did for these reasons.
- jerf 5y agoThis allows you to override the logic later. Public fields in a language where "x.y" means "directly access field y on value x" don't allow that; x.y forever means "directly access field x" and you can't later interpose code between attributes and the code accessing it. This isn't the only way of doing it, depending on your language. Python has a completely different mechanism where a class can start with a directly-accessed "y", but in a later version make it a property. (More than one, actually.) Some languages route all property accesses through something you can hook. Some languages simply automatically do what C# is doing here. Semantically and abstractly, there's no reason to every not be able to override a property access in later versions like that, because it is so darned useful. Unfortunately, performance wise, it's hard to beat a language that guarantees structure layout and guarantees that x.y can be compiled into a single constant memory load instruction, and unfortunately, you can't just wave "compiler optimization" at the problem and make it go away (considered in isolation this seems like an obvious solution but as usual as it starts interacting with all the other features it gets much harder than the simple cases). The higher performance languages have a strong reason to give people ways to get guaranteed direct struct member accesses.
- jdmichal 5y agoThough please note that if you "upgrade" anything from a field to a property, you need to recompile any dependencies. Otherwise they will obviously try to invoke the field that no longer exists, instead of calling the property methods.
- _old_dude_ 5y agoThe "dynamic" keyword [1] is my favorite blunder in C#. It's great if you are use it for COM interropt but it's awful otherwise. The code compiles but from time to time it fails at runtime and performance are sometimes Ok, sometimes not depending on the call stack. [1] https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/types/using-type-dynamic https://docs.microsoft.com/en-us/dotnet/csharp/programming-g...
- sterlind 5y agodynamic is amazing for the extremely niche use case of interop with dynamic languages. I had a system which executed Python scripts on devices using an orchestrator written in C#. With dynamic and IronPython, I could seamlessly unit test the whole enchilada without writing un-Pythonic Python or ugly C# wrappers.
- thomascgalvin 5y ago> [C#] feels slightly more like a "Java done right" This is how I feel about Kotlin.
- shellac 5y agoC# is an excellent contrast. It has always moved quicker than java (not hard), but that has left some features that in retrospect seem half baked. For example they needed some sort of function reference thing, so we had 'delegates', but then later we got lambdas with LINQ. And although LINQ has a lot of good parts, I'm not sure the expression bit was a good idea even people familiar with SQL linked it. And reified generics are nice for c#, but a right pain if you want to implement another language on the CLR which isn't very c#-ish. More recently I'm still not sure why, in a language with an extensive runtime and its own VM, they went with async / await rather than fibers or continuations like go and java. It was probably simpler to implement initially, of course. Even slow moving java shows that bad decisions have a cost down the road even if the features are unused: there can be monitors on any object to support synchronisation, serialisation similarly lurks around internally.
- tsimionescu 5y ago> More recently I'm still not sure why, in a language with an extensive runtime and its own VM, they went with async / await rather than fibers or continuations like go and java. It was probably simpler to implement initially, of course Async/await work much much better than goroutines for GUI programs, which was still a major market at the time this feature was added to C#. Since there is a single GUI thread where everything that touches the GUI must live, but you do want your application to have multiple other threads, you need to give the programmer this kind of control and can't rely on a more simplistic Go-style green threads runtime. I believe COM also has some similar requirements, but I am less sure than I am for GUI. Finally, C# has a lot of influence from the functional langauge community, so it's possible that async/await and Task values were a more appealing solution given those particular tastes.
- vips7L 5y ago> Since there is a single GUI thread where everything that touches the GUI must live, but you do want your application to have multiple other threads, you need to give the programmer this kind of control and can't rely on a more simplistic Go-style green threads runtime. Isn't that just a limitation of Go since its goroutines all run in the same pool? As far as I know, in the Java implementation you'll be able to create virtual thread pools from regular threads (i.e. the gui thread) and then have another virtual executor for the rest of your program. You'll still have the backend vs gui split but you won't have the entire async await split for the rest of your application.
- Mikeb85 5y agoWhy not start incorporating Kotlin? It's basically what you want, is an easy transition and has JetBrains' backing so the tooling is there...