Set<File> s = new HashSet<File>();
s.add( new File( "c:/temp" ) );
s.add( new File( "c:/temp" ) );
System.out.println( s.size() );
This prints 1.The C# code:
ISet<FileInfo> s = new HashSet<FileInfo>();
s.Add( new FileInfo( "c:/temp" ) );
s.Add( new FileInfo( "c:/temp" ) );
Console.WriteLine( s.Count );
This prints 2.They are line-for-line identical. IMO, Java prints the correct result. C# may have reasons for this behaviour, but when you're looking at the code, it's not obvious that two FileInfo objects for the same paths are not equal.
When I wrote KeenWrite[0], I chose Java because of all the reasons you mentioned, plus JavaFX. JavaFX is one of the richest cross-platform GUI libraries available for desktop applications, although it does have quirks.
Doesn't Java also have things that use reference equality? Arrays?
Yes. There are inconsistencies all over the place. In fact, OPs example of java.io.File is ironic, because that object had a number of issues and was somewhat replaced by java.nio.file.Path [1].
Even outside of that, file equality in general is fraught with a lot of subtlety. For example, should java.io.File equality be case sensitive or insensitive?
[1]https://docs.oracle.com/javase/tutorial/essential/io/legacy....
---
On a tangent, is there a reason why FileInfo does not override `Equals`?
E.g.:
var f = new FileInfo("image.jpg");
var set = new HashSet<FileInfo> { f };
f.MoveTo("image2.jpg");
Console.WriteLine(set.Contains(f)); // Would be false (sometimes)Here's another:
string path = "/tmp/filename.txt";
FileInfo f = new FileInfo( path );
File.CreateText( path ).Dispose();
Assert.True( f.Exists );
f.Delete();
Assert.False( f.Exists );
Astonishingly, the test fails because the result of Exists is cached. ¯\_(ツ)_/¯My expectation is that if I put two things that are identical---for all intents and purposes---into a set, only one copy is added to the set. Likewise, upon deleting a file, I expect that testing for its existence always returns false. Both of these expectations are based on my mental models for math and file systems.
I haven't tested the behaviour of caching file states in Java, but I suspect it will return false if the file is deleted. Point being, in my limited time with C#, I've found it to violate the principle of least astonishment in ways that Java does not.
I ask because the JVM is an amazing bit of technology that has been battle tested for decades. Would be hard to beat I would think.
- Data classes can become JVM records with the @JvmRecord annotation and some additional type constraints.
- Inline classes will certainly become Valhalla value types (hence the required @JvmInline annotation).
- Nullable types are supported with compile-time checks and additional runtime checks inserted by the compiler at time-of-use, and if Valhalla adds a nullability marker to the bytecode, Kotlin can support it.
- Coroutines/structured-concurrency already uses Executors under the hood, so it's likely that we'll have Loom thread support without any changes to the coroutines APIs (though the standard dispatchers will need to use virtual threads themselves). Coroutines themselves are CPS-transforms of ordinary code and don't need VM support.
- Tail-call elimination is supported by transforming to trampolines, something which the JVM will probably never support until Java needs it.
For example syntactic cooperative coroutines vs preemptive coroutines provided by the VM. Kotlin is now stuck with the colored function problem and has the stack trace issues that the Java team is able to avoid by not only being able to change the language.
That being said, I think they're both fine languages with different goals.
The language is completely closed and controlled by a single commercial software company and there is no community process involved in its evolution and design. I had believed that this business model of programming language design/ownership died decades ago when everyone abandoned all the bespoke commercial languages/IDEs of the 1980s and early 1990s. The way Jetbrains have scuppered the attempt to provide a reasonable vscode plugin feels like reliving the 1990s where the single company providing the language spec, compilers, IDE and tooling for "their" language and aggressively prevented others from providing alternative tools and compilers.
Also compile times are horrendous - even with modern hardware, the compiler barely seems to be able to manage much more than a few 1000 lines/sec. Again, my age means I remember decades ago when compilers/IDEs advertised their performance in terms of 100,000s of lines per second. This means edit/compile/debug workflow is very painful once your project grows to non-toy sizes.
I also grew to dislike the ethos of the "community" which basically seemed to involve condescension and passive aggressive responses to to any questions regarding the design of language features particularly by Jetbrains employees.
Kotlin is undoubtably a more "modern" feeling of development than Java (or C++ for example) but I'm not sure such vendor lock-in is worth it given many other languages are catching up (including Java) or exceed it. Also I used C# for about a year subsequently and realised that Kotlin stole most of its best features from C#. Languages like Rust, Zig, Swift, etc. are just as "modern".
All in all there are less resources on Kotlin but too many things they want to do. Not only are they building the language but they have to reinvent everything because they don't work on Multiplatform.
It used to be simple - a better Java (so it claims). Now I'm not so sure what the direction is.