Surely that's just contravariance, though? You can't cast []string to []any because that would allow you to write non-strings to it.
For those who aren't familiar with the issue, in Java you can assign an array of a subclass to a variable declared as an array of the superclass, which leads to issues if you actually try to mutate it. Imagine if Cat and Dog both inherit from Animal, assigning a Dog[] to an Animal[] is totally valid, but then setting one of the elements to a Cat will throw an an exception.
For what it's worth, I'm not sure this is even something I'd consider a "notorious" problem with OOP because the solution is really simple and wouldn't break anything else if done correctly from day one: just don't allow using arrays of subtypes in a place where an array of its supertype is expected. This was already known at the time Java was designed, and I'm pretty sure the people who designed Java knew it too; they just didn't pick the right way to handle it in my opinion. There's nothing inherent about OO that makes this bug that much harder to deal with than any other language because it can happen in any paradigm with subtyping (as demonstrated by the fact that it could have been present in Go if they did allow casting arrays of interfaces in that way).
get :: Int -> T
Here, T is on the right/return side, therefore an immutable array type would be covariant. But a mutable array also has a set :: Int, T -> void
which has T on the left/parameter side and therefore requires contravariance (and you cannot have both, therefore you get invariance).
But the issue is not with mutability, since you could just as well have something like setImmutable :: Int, T -> Array(T)
and you still wouldn't be able to make Array(T) covariant.And for the record, it is only raw arrays in Java that have this issue, generic types like List<T> are invariant (of course you can explicitly ask for a List<? super T> if you want to only call "setter" type methods on it, or List<? extends T> for getters, aka methods where T appears only on return side).
So immutability resolves the covariance problem, I think?
One of the variances is safe if you only read, and one is safe if you only write.
object[] array = new string[10];
// throws a run-time exception
array[0] = 10;Other data structures like List<T>, Span<T>, etc. do away with covariance. There's an upcast for ReadOnlySpan<T> but only because it's zero-cost and does not introduce the issues stemming from covariance.
Luckily, you almost never see someone use array covariance beyond occasional object[] upcasts (and the compiler is also good at reasoning whether to insert covariance checks or not).
Thus having high compatibility with how Java used to be was a big factor designing C# 1.00
WinRT was supposed to replace .NET by the original goals, after the Sinofsky and his followers took over Windows development after Vista, it has been COM as the main API.
"Turning to the past to power Windows’ future: An in-depth look at WinRT"
https://arstechnica.com/features/2012/10/windows-8-and-winrt...
However as we all know by know, it didn't went down as expected.
Now those blog posts are kind of gone from their original hosts.
F# HOPL paper,
https://fsharp.org/history/hopl-final/hopl-fsharp.pdf
Original blog post on way back machine, including the link to "MSR White Paper: Proposed Extensions to COM+ VOS (Draft)" paper.
https://web.archive.org/web/20190111203733/https://blogs.msd...
There was mostly no reason to cause unnecessary code churn to rename pre-existing code with complus-named variables inside dotnet/runtime. External-facing features and documentation never reference it. For compatibility reasons it still recognizes env. variables prefixed with COMPlus_ alongside DOTNET_ though.
See: https://github.com/search?q=repo%3Adotnet%2Fruntime%20complu...
In a similar vein, NativeAOT code still prominently references project RedHawk (these are slowly being renamed).
At the same time, JVM has embraced the polyglot ecosystem CLR was supposed to be, while C# seems to have sucked the life of all those language implementations demoed at the launch back in 2001, and .NET SDK being offered on computer magazine CDs.
Which is kind of interesting, how things have changed 25 years later.
At least we finally have cross platform support (ignoring Mono and DotGNU efforts), and good AOT instead of NGEN, which should have been there on .NET 1.0.
> VSCode Java experience is still ahead of C# DevKit thanks collaboration with Red-Hat, and doesn't require an additional licence.
I'm not sure if you're intentionally attempting to make inflammatory replies or something in what I said rubbed you the wrong way.
(for other readers - this marks me posting for 20th time here that DevKit is an optional product and thousands of developers are happily coding in C# in VS Code and VSCodium, Neovim and Emacs without ever running into it)
I am stating facts, do you want links to .NET team interviews where they assert it is a business decision VSCode is never going to achieve feature parity with VS for .NET?
VSCode for Java doesn't have such artificial constraint, hence the better tooling, mainly implemented by Red-Hat.
C# DevKit being optional doesn't change the fact specific features are only available when users opt into using it, with a corrrespondig Visual Studio license.
And yes, this irritates me, because I feel it is a disservice to .NET community how Linux and macOS developers are kind of 2nd class, not by .NET team themselves, but higher up Microsoft management.
And also, have you tried writing Java in VS Code? I have and it is overall worse (read: less stable) than just using IntelliJ Idea in a way that isn't an issue when doing so in C#/Go/Rust/TS.
Lucky one I guess.
I have used it, its stability issue is orthogonal to feature parity, being whole Eclipse running headless, which is the point, features.
This how generic methods like Arrays.sort() are implemented.
I think Go does the right thing to make this allocation and assignment explicit, you may be a little less surprised with how the program actually behaves. https://go.dev/play/p/PzuBpM66VX2
The O(n) loop is here: https://github.com/golang/go/blob/215de81513286c010951624243...
But why did Go pick the same syntax for cheap conversions and expensive ones, though? I'd expect this to be a standard function, not a type conversion.
dur := time.Second * time.Duration(2)
headers := http.Header(map[string][]string{})
httpDir := http.Dir(filepath.Join(parts...))
In all of these cases, it's just a type-cast which is zero-cost, and I think that's what makes it feel surprising that casting between strings/runes specifically incurs more significant computation than any other cast.