NHacker Next
  • new
  • past
  • show
  • ask
  • show
  • jobs
  • submit
A better (than Optional) maybe for Java (github.com)
_kidlike 32 days ago [-]
`then` is definitely less intuitive than `map` considering that you actually want to, well, map to something else.

Semantically, `then` would be equivalent to `ifPresent`, but, well, then both are intuitive.

funcDropShadow 32 days ago [-]
Nothing is intuitive on its own. Intuitiveness is a property of the relation between a thing and and some subject. Whether `map` is more intuitive than `then` depends on that subject. Without assuming a target audience, it is futile to design a library to be intuitive. Intuitive is that, for which we already have built an intuition.
ljlolel 32 days ago [-]
In UX, there is nothing intuitive, only familiar

Although have you seen that video of a chimpanzee browsing Instagram?

Or a parrot using zoom?

ivan_gammel 32 days ago [-]
Interesting attempt, however:

1. There was no need to implement Set interface to support foreach loop. Iterable would be sufficient. Set is too specific and is not an obvious choice (for return type interoperability in subclasses sometimes it would be more convenient to have List).

2. Moving from isPresent/get to try/catch checked exception will produce worse result. Either you wrap ‘get’ immediately and get more verbose code, or you catch somewhere else and loose the context and readability. In “throws Exception” methods absence of stack trace will be painful.

3. Renaming ‘map’ to ‘then’ is too late. “Then” was used in functional style libraries more than 15 years ago, Java 8 settled the naming convention and it’s better to follow it.

4. What Optional is often missing is the context of empty state. It would be cool to have an implementation of None with a Throwable cause (and orElseThrow throwing it wrapped).

occz 32 days ago [-]
The real improvement is to lift nullability up to the type system. That way, every type acts as an optional by default, and the computer can infer when a nullable type has been null-checked.

This is what Kotlin does - it's truly freeing to work with.

DarkNova6 32 days ago [-]
They are slowly getting there. See the JEP draft: Null-Restricted Value Class Types (Preview)

Source: https://openjdk.org/jeps/8316779

But it is already possible today using the Spring annoation "NonNullApi" on a package level. Then, you can allow nullable fields via @Nullable.

It's not perfectly elegant, but it works surprisingly well.

pjmlp 31 days ago [-]
Usually I have bigger fish to fry in enterprise projects than a couple of NullReferenceExceptions.

What would be truly freeing is getting the right set of folks on the projects.

ajkjk 32 days ago [-]
"the real fix is to move from the stone age to the iron age"

...suffice it to say, there are even better ages

occz 32 days ago [-]
I don't know, I think Kotlin strikes a pretty good balance as far as languages go. What's your preference over it?
ajkjk 32 days ago [-]
oh I think it's fine. I just find it a bit odd to be saying "the thing we should have from our type system is that it's a type system, it's truly freeing to work with". Like... yeah of course we should but it's a bit sad that we're getting exciting over basic functionality like that in 2025.
dehrmann 32 days ago [-]
> The exception that is raised when an empty Maybe is used is a checked exception so you don't forget to handle it.

I think they acknowledged get() should have been getOrThrow() so it's clear what can happen, but I don't know if making it checked is an improvement.

> It implements the Collection interface, so it can be accessed with a for-loop.

I'm curious what the use cases are for this. I've used Optional, it can be annoying, it's mostly around it being verbose and APIs being inconsistent. It was never wishing I could treat it as a collection.

kelseyfrog 32 days ago [-]
I'd imagine it's a poor-man's do notation.

When it comes to structured programming, languages without a do syntax are considered incomplete. It's like programming without ifs.

AtlasBarfed 32 days ago [-]
Fro what language? Is that like groovy with?
eru 32 days ago [-]
Do-notation is a thing in eg Haskell.
hackingonempty 32 days ago [-]
Like Scala's for-comprehension.
porridgeraisin 32 days ago [-]
Yeah I don't get the iterator thing either... Saw the implementation and I'm not sure what the usecase would be.

They have essentially implement a single element iterator for Some and a zero element iterator for None.

ai_ 32 days ago [-]
It's useful for combinators, like flatMap. For instance if you want to flatten an iterator of optional values into the values of all some elements.
dehrmann 32 days ago [-]
Is it worth using a custom library so you can do

.flatMap(Maybe::stream)

instead of

.filter(Optional::isPresent).map(Optional::get)

sedro 32 days ago [-]
It's useful and very common to use. For example, you could concatenate together command-line argument flags that may or may not be present.
stickfigure 32 days ago [-]
`map()` makes Optional congruent with java Streams. Optionals are very frequently used with Streams, eg:

    someList.stream().map(Thing::foo).findFirst().map(Other::bar)...
And checked exceptions are a scourge. There's a reason post-Java languages like C#, Scala, and Kotlin abandoned them. Even lombok offers @SneakyThrows.

The Java Optional<?> is pretty good as-is. The main improvement I'm make is that it needs to be Serializable. And woven into the core collection classes.

crummy 32 days ago [-]
Why do you want Optional to implement Serializable?
stickfigure 32 days ago [-]
Literally to make it able to be serialized by Java.

There are many legitimate applications for Java serialization which do not suffer security concerns. You should never expose serialization for public APIs but that leaves private APIs and private storage systems (think message queues, disk caches, internal RPC, etc).

For private serialization, Java serialization has many advantages over something like JSON. You can serialize object graphs without concern for cycles. The contract is simple (it serializes fields, as opposed to dealing with weird bean naming conventions). It handles types and structures automatically. `transient` is built into the language. Polymorphism just works.

We use it heavily for ephemeral storage. It's great.

Timwi 32 days ago [-]
To make it able to be serialized?...

Am I missing something?

crummy 32 days ago [-]
Most of the serialization libraries I use (Jackson, gson) ignore the Serialization interface. I think it's only used for Java's now-rarely-used native serialization functionality.
lucumo 32 days ago [-]
Only Java's built-in serialization still requires Serializable. And Java's built-in serialization is fundamentally vulnerable and should never be used.

Newer libraries dropped the need for Serializable, because whether or not an object is serializable is not just dependent on its class, but also on the features the serialization library supports.

stickfigure 32 days ago [-]
> Java's built-in serialization is fundamentally vulnerable and should never be used

If you added "...for public APIs" then I would agree. But that represents only a tiny portion of the use cases for serializing objects. Java serialization excels at many of them.

lucumo 32 days ago [-]
If you have FULL control over the serializing code and the serialized file during the entire time between serialization and deserialization, it can be safe.

Put the file on the filesystem with incorrect permissions, transfer it over unencrypted HTTP, or do any number of things that allow others to mess with your data and you're screwed.

Don't use it. It relies on the unsafe data to tell it what class to unmarshall to. If any class on your classpath does anything weird in its deserializing code, you've lost.

Nowadays it's possible to filter the classes that can get deserialized, but: 1) there's still way too much Java 8 code around that doesn't have that filter; 2) those were the same JDK-wide until Java 17; and 3) worst of all, nobody uses them.

Using Java serialization is like playing the knife game. You can win. But you'd better not make even a tiny mistake.

stickfigure 32 days ago [-]
This is dumb. If you're using it for internal RPC, or putting it in a message queue, or putting it in memcache, etc etc then you control both sides. A huge amount of business processing works like this. It's totally fine.

Not every protocol needs to be designed for the REST use case. We have REST (and gRPC, and thrift, and avro, and many other protocols) for that. Use the correct tools for the job and stop the FUD.

lucumo 31 days ago [-]
Defense in depth is a thing.

Trusting the message queue to be the only security barrier into your system is not great. Wouldn't be the first time one of those gets misconfigured. When that happens, using Java serialization leaves your system open in a way that other serialization libraries just don't.

stickfigure 30 days ago [-]
Each defense intervention needs to be weighed against its cost, and also against the threat model. If the attacker can inject arbitrary content into the message queues of most business applications, they already have the keys to the castle. And all of those other serialization libraries come with costs and tradeoffs.

I'm guessing you work in security and don't actually build production systems for a living?

lucumo 30 days ago [-]
> Each defense intervention needs to be weighed against its cost,

What cost? Jackson for example is just as easy - if not easier - than Java serialization. It's widely used (therefore well tested), actively maintained and well-designed.

> If the attacker can inject arbitrary content into the message queues of most business applications, they already have the keys to the castle.

They can make your application follow different steps of the application's own rules. Java serialization is one badly designed class on the classpath away from an RCE: in which case it can completely ignore your application's rules.

For example, if you have a compromised message queue for creating users, a good serialization lib won't stop the attacker from creating an admin user, but it will stop the attacker from dumping your user database and TLS private key. Java serialization will not stop that at all.

That's not hypothetical, BTW. About a decade ago a whole bunch of exploits came out that used Java's serialization and popular libraries on the classpath. Many resulting in remote code execution. That's why you can now set an ObjectInputFilter or `jdk.serialFilter`. But those don't save anybody when they're not set. And they are not set by default.

> I'm guessing you work in security and don't actually build production systems for a living?

You guessed wrong. I've built many production systems and am still building production systems.

Look, I've frequently been annoyed by the same thing you're accusing me of: overzealously trying to reduce risks to the point of ridiculous expense. But that's not what this is. There is very little benefit to using Java serialization, and it adds weaknesses that are unnecessary. When building something new, using a different solution significantly hardens your system at essentially no extra costs.

It can be more costly to retrofit existing systems. That's a situation where the filters can be useful. The whole code then becomes the type of code nobody wants to have, but that we all have too much of anyway. We call it legacy and strive to have less of it next time.

stickfigure 30 days ago [-]
I'm just going to quote myself from the thread above:

> You can serialize object graphs without concern for cycles. The contract is simple (it serializes fields, as opposed to dealing with weird bean naming conventions). It handles types and structures automatically. `transient` is built into the language. Polymorphism just works.

I like Jackson more than most. And there are many contexts in which JSON is the better answer. But there are also many contexts in which Java serialization is a better answer. Even with the security considerations.

evidencetamper 32 days ago [-]
You don't need your optional to be serialized - it's just a container. You need what's inside your optional to be serialized.
derriz 32 days ago [-]
I really dislike the use of exceptions - particularly checked exceptions - to handle control flow for things like this. I mean, it's not EXCEPTIONAL to have an empty Optional, right? Their use here is an anti-pattern to my eye.

Java (the language) should just drop the notion of checked exceptions. It would be fully backward compatible as the checked/unchecked distinction is a language feature not a JVM one.

They simply don't work with Stream and cause abstraction leaks everywhere (e.g. you have to handle IOExpection for operations on StringWriter). It obfuscates flow control.

Anyway the problem with Optional is not going to be fixed by renaming API methods and fiddling like this (sorry to be harsh). The reason Optional is broken is because there is so much legacy APIs which use null to represent "no result" and until all of these APIs are changed/deprecated, then Optional will never be a very useful tool.

As others have commented, the correct solution would be to ditch Optional completely along with the mass of flavors of @Nullable, @NotNull, etc that everyone uses along with having to use package_info.java everywhere and just make "nullability" part of the type system.

Kotlin got it right here. But it would be a breaking change in Java to make not-nullable the default. They could do it the opposite way to Kotlin - add a marker for "not-nullable" instead of one for "nullable" - e.g. "String!" would be a not-nullable String instead of say "String?" representing a nullable string.

dfe 29 days ago [-]
I agree with you on your first statement. Exceptions for control flow is an awful API.

I also wholeheartedly agree with your comments that nullability should be a first-class language feature, part of the type system. I think what you describe is one of the active JEPs.

* Plain old String is "I don't know if it's nullable or not, so I'll let you dereference it without checking, but I may issue a warning.

* String! is "You're telling me it cannot be null so I will enforce that it is not null on the way in (e.g. when converting from String) and will issue no warning on the way out because it cannot be null.

* Finally, String? is "You're explicitly telling me it can be null, so I will force you to do a null check before converting to a String!"

But that's only part of it. I think Java desperately needs a ?. operator (Optional.map but without the Optional). I also think it needs a ?? operator (Optional.orElse but without the Optional).

So far I think Optional is more of a detriment to Java than a benefit. It feels like it was hacked in because without it some of the Stream APIs would be nightmarish given Java's current type system, and getting streams into the standard library API was too important a feature to wait for fixing the long-standing issues with nullability.

The only thing I disagree with you on is I do think there is some merit to checked exceptions when used sparingly. Capturing the idea that a method can fail for a reason that has to do with the program's input or environment (checked exception) vs. a reason that has to do with the program's code and cannot be solved without changing the program's code (RuntimeException) is a pretty neat thing.

I think the Streams API could have easily implemented terminal operations like forEach(ThrowingConsumer<E,X>). This could still be added.

I also think that the <X> ... throws X pattern should accommodate a union type like IOException|ParseException and that this should be inferred so that in this example of a throwing Consumer, whatever checked exceptions the method throws simply become the checked exceptions of the forEach method.

Conceptually, these are straightforward ideas. I suspect the limiting factor is figuring out how in the world to actually implement what I just described.

DarkNova6 32 days ago [-]
This is an old suggestion. You don't have the slightest idea what kind of rabbit holes this will lead into. This has been discussed time and time again.

The much better approach is to keep it as-is but make Exceptions composable:

switch( this.networkOperation() )

case throws IOException ex -> "invalid"

case String expected -> return expected;

case Object obj -> throws new IllegalArgumentException(obj);

You get the best of both worlds. The caller is forced to handle expected errors at call-site (aka, where you have the most information). But you can still delegate the error to a higher level, such as Controllers where the error gets turned into a "500 Server Error".

The problem really only is that you are currently forced into creating a new try-catch block. If that goes away, you are essentially dealing with sum-types. This will be more elegant than heralded languages such as Go where you slavishly write "err != nil" statements at every turn.

derriz 32 days ago [-]
"You don't have the slightest idea what kind of rabbit holes this will lead into."

Instead of making assumptions about what I know or don't know about programming language theory and type systems, could you list these rabbit holes?

Java inspired languages like Kotlin, Scala and C# all considered checked exceptions and all decided to drop them and I've never heard users of any of these language express any wish to re-introduce them. I've used all three professionally and I have no idea what "rabbit holes" you're talking about?

In fact there isn't a single widely used language besides Java that feature checked exceptions. Arguably Eiffel had them but that's seriously stretching the definition of "widely used".

m11a 31 days ago [-]
> In fact there isn't a single widely used language besides Java that feature checked exceptions.

Not in Java's form, but I'd argue Rust's Result type basically achieves the same effect but with less syntax. A function call can return an error variant, and the caller must handle the case (even if that's just propagating it up with `?`), as opposed to letting it silently flow up the call stack (which is more like a Rust panic).

And I'd argue that Rust's error handling is excellent. The programmer is always forced to acknowledge function calls which may produce an error, yet is also able to say "I don't care" without much syntactic overhead.

stickfigure 32 days ago [-]
This doesn't seem any different from try/catch? The syntax differences are minimal.

I don't mind try/catch, but I agree that checked exceptions should be dropped. Exceptions are for exceptional situations, which are myriad and rarely need to be handled except at some upper level (return 500, show error dialog, etc).

ivan_gammel 32 days ago [-]
Oh, that actually does look different. Switch expression with exceptions would allow compact use of checked exceptions in method chaining.

List<URI> pages… var content = pages.stream().map(uri -> switch(fetch(uri)) { case Page model -> return model; case throws IOException -> return Page.notFound(uri); }).toList();

ivan_gammel 32 days ago [-]
> the correct solution would be to ditch Optional completely along with the mass of flavors of @Nullable, @NotNull

How would you suggest to implement Stream::findAny without Optional?

derriz 32 days ago [-]
Using my suggestion, the signature would simply be "T findAny();" - while "T!" would represent non-nullable T. So the opposite of the Kotlin/Typescript/etc. way where the default is not-nullable and you'd have something like "T? findAny();".

It would be a language level change and would require language level syntax extensions to provide mappings between T and T!.

Like how we're used to having to add "final" to most variable declarations, you'd add "!" to a class type indicate not-null. Contra-variance would allow you to add ! to return values without breaking interface compatibility so you could migrate your code base in steps. Actually to be honest I'm just throwing this idea out there, I haven't given it deep thought.

Without language level support, Optional is a broken design. You've just multiplied the state space: the Optional instance can be null, the Optional instance can be not-null but empty, the Optional instance can be not-null and non-empty but the content is null and finally the Optional instance can be not-null and non-empty and the contained value can be non-null. Java's type system doesn't distinguish.

ivan_gammel 32 days ago [-]
>Actually to be honest I'm just throwing this idea out there, I haven't given it deep thought.

I think the problem is much more complex if done properly, Java way, with full consideration. E.g. Optional has fluent interface which often becomes useful to avoid lots of nested if’s. To emulate chaining with nullable values you do need ‘?’ syntax.

>the Optional instance can be null

When return type is Optional, it is an error in 100% cases to return null, so it’s a valid case for NPE. A vary rare problem.

> the Optional instance can be not-null and non-empty but the content is null

Optional of null content is empty by design. Did you mean something else?

derriz 32 days ago [-]
No doubt the problem is more complex and like I said would need language level syntax support.

Sorry yes you're correct, optional containing null is the same as an empty optional. So there are 3 cases, not 4.

But saying that "it's a valid case for NPE" missed the point I believe as you're taking about dealing with the issue at runtime. The killer feature of having language level support for distinguishing null and not-null is that these errors are flagged at compile time, not runtime.

ivan_gammel 32 days ago [-]
>But saying that "it's a valid case for NPE" missed the point I believe as you're taking about dealing with the issue at runtime.

What I mean is that this issue (null instead of Optional) is rare enough not to bother about it and let NPE happen. Language support for null/non-null values in general would be nice, of course.

norswap 32 days ago [-]
While I agree exceptions should not be used for control flow except in the rarest of circumstances (every rule has exceptions — pun fully intended), I think checked exceptions are very useful.

I wrote a whole article about this, way back when: https://norswap.com/checked-exceptions/

But for the tl;dr: checked exceptions represent somewhat expected issues, things like IO errors. There are two okay ways to handle those: checked exceptions and result types, and one bad way: unchecked exceptions.

Unchecked exceptions end up being undocumented in the API, and people forget to handle them.

Result types add a lot of ceremony, as you have to unwrap them at every level of the call stack. I've seen code dominated by error checking logic many times in C and Go (and the frequent alternative is to ignore error, which is easy in C).

Checked exceptions are much less verbose, you just let the exception pass through and annotate the function signature with the checked exception. It's type-safe, self-documenting and easy.

Unchecked exceptions "leak", checked exceptions propagate at the type-level, which is exactly what you want — making sure every caller is aware of what exceptions might occur and letting them make an explicit decision to handle or pass the buck upwards.

By the way, checked exceptions are coming back in favour with "effects" which are basically a generalization of checked exceptions beyond the realm of errors, trying to encode things into the type system.

derriz 32 days ago [-]
These arguments have been going back and forth forever. I don't think either of us would be able to change each other's position on this based on arguing either way.

I'll take a different tack - look at the empirical evidence. If checked exceptions were a good/useful/helpful language feature, then the feature would have been adopted by other languages, especially new ones. But this simply hasn't happened. Java is unique in having checked exceptions.

Wouldn't you think that there would have been proposals to introduce checked exceptions for C++, Python, JavaScript, C#, and Rust, Kotlin, etc. if they were a useful software engineering tool?

dfe 29 days ago [-]
I used to think checked exceptions were stupid, so I'd catch and wrap them in a RuntimeException at the first opportunity just to get rid of them.

These days I've come around to your viewpoint that checked exceptions are great because all you have to do is declare them until you get to a point in the call hierarchy where you either can handle them or it's impossible to handle them so you wrap them.

In some cases, like with reflectively-invoked JUnit test methods, they only need to be declared because JUnit has its own exception handler. But you wouldn't believe the crazy amount of test code I see that eats exceptions instead of declaring them.

I think the confusion comes because with very simple programs you only ever see the point where you have to handle the checked exception, so a habit of writing catch blocks forms. It's only when designing libraries that you would declare checked exceptions as part of your method signatures and just allow them to naturally propagate. Therefore new Java programmers see all these extra catches and think it's just a burden they have to meet.

Another thing about Java that's bad for casual coding is that it exits 0 (success) when all non-daemon threads have ended, even if those threads ended because of an exception. It would be really nice if there was some internal flag set by the default uncaught exception handler that would cause a non-zero exit later when all threads are finished (which might be right then). Maybe I should submit a JEP.

blastonico 32 days ago [-]
> The method names are more intuitive: e.g., then instead of map

But map makes total sense, considering that maybe is a monad.

edflsafoiewq 32 days ago [-]
Rather than monads, map is more likely to be familiar from sequences, and an optional is just a sequence with length < 2.
eru 32 days ago [-]
Well, monads get their map from functors, and they call it 'map' (or fmap) because of map on sequences.
Jaxan 32 days ago [-]
I would expect different types of map and then:

    map :: (a -> b) -> Maybe a -> Maybe b
    then :: (a -> Maybe b) -> Maybe a -> Maybe b
Although for Maybe these are not too different.
coin 32 days ago [-]
“then” is definitely less intuitive
puchatek 32 days ago [-]
Intuition is in the eye of the beholder
eru 32 days ago [-]
Well, it only needs to be a functor (in the Haskell sense) for map to make sense.

(Of course, all monads are also functors.)

voidhorse 32 days ago [-]
True, but I would not be surprised if the vast majority of Java programmers have no clue what a monad is.
chii 32 days ago [-]
> no clue what a monad is.

which is a good opportunity to introduce said nomenclature, and ideas to them, rather than renaming said method to something more "palatable".

Dansvidania 32 days ago [-]
In my experience just name-dropping monads in non functional-programming oriented circles will get weird looks.

EDIT: I would even argue, as a fan of FP, that it's not immediately obvious how this terminology or concept even helps, from the point of view of a non purely functional programming language

mrkeen 32 days ago [-]
Because the alternative to using one name is using more than one name. These days I'm pretty sure I'm using `select` to mean `map`.
xigoi 32 days ago [-]
You don’t need to mention monads, just imagine an Optional as a list with at most one element.
32 days ago [-]
stemlaur 32 days ago [-]
I would make the abstract class "Maybe" a sealed class with None and Some being the only permitted implementation So that clients can use pattern matching (enhanced switch)
Hackbraten 32 days ago [-]
Very good point.
dfe 29 days ago [-]
This seems to be worse in every way to Optional.

The throwing of a checked exception is ludicrous. It's a classic case of abusing checked exceptions for flow control. The right approach is an isPresent() or isEmpty() call followed by a get() when you know it's present. Static analysis can ensure you don't screw this up.

Similarly, using then and thenMaybe instead of map and flatMap means it now has its own terminology different from Stream.

Being able to iterate it is dubious. You can already .stream() an Optional (to an empty or 1-element stream). You can also if (o.isPresent()) { o.get(); } which is hardly burdensome. I'm trying to figure out how a for-each loop is an improvement. But if you must: o.map(Collections::singleton).orElse(Collections.empty()). Or o.stream().toList().

I applaud the author for experimenting with different API designs, but this one is just not good. It causes more trouble than it solves.

Blackarea 32 days ago [-]
Checked exception in a Optional.get is really the worst idea that you could possibly come up with.

Have a look at vavr (https://github.com/vavr-io/vavr) They did a fantastic job and the DX is so much better than anything java std has to offer. They have immutable equivalents for pretty much any java util data structure as well as either try option etc. To me the one lib that makes java actually feel fresh.

gylterud 32 days ago [-]
Vavr is nice! But I understand the want to make the get exception checked. It makes it so that you can use try/catch as a Java-man’s do-notation, and not fear having forgotten to deal with the None case.

You can then make lots of utility functions which all get without handling it (only declare that they throw) and then you compose these into larger functions which make sure to catch at the end.

Having to declare it makes it really clear what the function actually does.

Blackarea 32 days ago [-]
Can you provide an example. I just don't see it tbh. Especially since closures in java really don't work with checked exceptions at all.

That's why vavr avoids it at all costs. Eg: ```java assertEquals( Vector.of(1, 3), Vector.of(Some(1), None(), Some(3)) .filter(Option::isDefined) .map(Option::get) ); ```

If `Option.get` was throwing a checked you'd always have to wrap it in try-catch. I understand that this is a break with the type system (meaning it is not strong typed Maybe/Option in that sense). But otherwise you'd be worse of than with stupid null checks IMO.

DarkNova6 32 days ago [-]
I really hate the inclusion of a "FastException" and "UnsafeUtils" class.

Many developers will consistently make the wrong choice thinking their complex (but cold) execution path needs to be extra sleek and fast. But the reckoning comes during debugging (most likely by somebody else) where you have extra levels of indirection and non-expected violations of typically default behavior.

rubenvanwyk 32 days ago [-]
Or... Just use Kotlin?
gf000 32 days ago [-]
Which has worse no real pattern matching like Java has?
rhdunn 32 days ago [-]
I'd like Java to add support for the null coalescing operator `?.` and associated `!.` and `?:`. -- I find this easier to use and read than using Optional or null check code.

I find heavy use of Optionals for nullable values can quickly overwhelm the codebase and make it hard to read the control flow. Especially when interacting with other parts of the codebase.

E.g.

    var baz = foo?.bar?.baz ?: return false;
vs something like:

    var baz = foo.map(f => f.bar).map(b => b.baz).getOrElse(null);
or using `then`.
Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact
Rendered at 15:17:34 GMT+0000 (Coordinated Universal Time) with Vercel.