Vavr: Add Try.withResources().run() for void functions

Created on 4 Sep 2018  路  5Comments  路  Source: vavr-io/vavr

Currently if you want to run a computation that doesn't return a value you have to do

final Try<Void> aTry = Try.withResources(() -> DriverManager.getConnection("")).of(conn -> {
    System.out.println("Ok");
    return null;
});

I propose to add something similar to Try<Void>.run(CheckedRunnable runnable) to simplify the above to

final Try<Void> aTry = Try.withResources(() -> DriverManager.getConnection("")).run(conn -> {
    System.out.println("Ok");
});

I could contribute if you agree to accept this enhancement.

question

Most helpful comment

@yarulan I understand your point.

Libraries' purpose is to make life easier for the users

It is an unequal trade: a bit syntactic sugar for performance overhead:

Try.withResources(() -> DriverManager.getConnection("")).run(conn -> System.out.println("Ok"));
  • 1 new TryWithResources1 class instance
  • 1 lambda instance () -> DriverManager.getConnection("") stored in 1 instance variable
  • 1 new Try instance by calling run
  • 1 new lambda instance conn -> System.out.println("Ok")

Now imagine we pass 8 resource suppliers. Then we have

  • 1 new TryWithResources8 class instance
  • 8 lambda instances () -> ... stored in 8 instance variables
  • 1 new Try instance by calling run
  • 1 new lambda instance (r1, ..., r8) -> System.out.println("Ok")

= n + 3 instances = O(n)

This does not scale well.

If we use Try.run(\) we have only 2 instances = O(1). It is my responsibility to get this right.


Regarding the lines of code, you are exaggerating a bit...

Try.withResources(() -> resource1, () -> resource2, () -> resource3)
    .run((r1, r2, r3) -> {
        // n lines of code here
    });

vs.

Try.run(() -> {
    try (var r1 = resource1; var r2 = resource2, var r3 = resource3) {
        // n lines of code here
    }
});

P.S. I have another proposition: remove collections from vavr.

It took a great amount of time for me to get clear, take the step and reduce the API surface of Vavr. Please don't understand me wrong, humans are fear-driven - they are collectors and don't want to loose s.th. If I'm able to get beyond that, there is lots of space for new things. It took nearly 40 years until I got that.

Please take a look at the comparison between Scala's Try, Vavr's Try and Java's Optional (which is very similar to Try). We should not try to be more clever than the language/native library architects.

vavr-control-api

Reducing the API surface area is not only good for me (as maintainer). It also makes learning of the API easier.

screen shot 2018-09-10 at 19 55 36

You have to trust me - it is the best solution I can imagine.

All 5 comments

Hi Yaroslav,

thank you for your suggestion, I鈥榲e also thought about it.
As you may have read already on our blog, we want to reduce our API surface area (for several reasons).
Namely, we will remove redundant verbs.

Try.withResources will be replaced by using Java鈥榮 try with resources directly:

Try.run(() -> {
    try (var conn = DriverManager.getConnection("")) {
        System.out.println("Ok");
    }
});

You see, it is all there already. We are able to

  • remove N types Try.WithResources1..N
  • remove N methods Try.withResources
  • we use native Java where possible, instead of introducing redundant proprietary API
  • we completely remove the dependency of Try to CheckedFunction1..N

Therefore I will close this issue.

Thanks again!

Hi @danieldietrich, thanks for the explanation. I'm sorry, but I don't understand your reasoning. I don't see how removing functionality can help your users to achieve their goals. That change will change single line of code

Try.withResources(() -> DriverManager.getConnection("")).run(conn -> System.out.println("Ok"));

into 5 lines

Try.run(() -> {
    try (var conn = DriverManager.getConnection("")) {
        System.out.println("Ok");
    }
});

P.S.
I have another proposition: remove collections from vavr. You will be able to

  • remove N types Travelsable, Seq, LinearSeq, IndexedSeq, Queue, Stream, List, Array, Vector...
  • remove N*M methods from classes above
  • use native Java collections where possible, instead of introducing redundant proprietary API

P.P.S.
Libraries' purpose is to make life easier for the users, not for the authors.

@yarulan I understand your point.

Libraries' purpose is to make life easier for the users

It is an unequal trade: a bit syntactic sugar for performance overhead:

Try.withResources(() -> DriverManager.getConnection("")).run(conn -> System.out.println("Ok"));
  • 1 new TryWithResources1 class instance
  • 1 lambda instance () -> DriverManager.getConnection("") stored in 1 instance variable
  • 1 new Try instance by calling run
  • 1 new lambda instance conn -> System.out.println("Ok")

Now imagine we pass 8 resource suppliers. Then we have

  • 1 new TryWithResources8 class instance
  • 8 lambda instances () -> ... stored in 8 instance variables
  • 1 new Try instance by calling run
  • 1 new lambda instance (r1, ..., r8) -> System.out.println("Ok")

= n + 3 instances = O(n)

This does not scale well.

If we use Try.run(\) we have only 2 instances = O(1). It is my responsibility to get this right.


Regarding the lines of code, you are exaggerating a bit...

Try.withResources(() -> resource1, () -> resource2, () -> resource3)
    .run((r1, r2, r3) -> {
        // n lines of code here
    });

vs.

Try.run(() -> {
    try (var r1 = resource1; var r2 = resource2, var r3 = resource3) {
        // n lines of code here
    }
});

P.S. I have another proposition: remove collections from vavr.

It took a great amount of time for me to get clear, take the step and reduce the API surface of Vavr. Please don't understand me wrong, humans are fear-driven - they are collectors and don't want to loose s.th. If I'm able to get beyond that, there is lots of space for new things. It took nearly 40 years until I got that.

Please take a look at the comparison between Scala's Try, Vavr's Try and Java's Optional (which is very similar to Try). We should not try to be more clever than the language/native library architects.

vavr-control-api

Reducing the API surface area is not only good for me (as maintainer). It also makes learning of the API easier.

screen shot 2018-09-10 at 19 55 36

You have to trust me - it is the best solution I can imagine.

@danieldietrich thanks for the response and sorry for being rude.

On performance: that's true that there are few class instantiations. But if they are performance bottleneck of your application then I can only congratulate you. Resources are usually some IO, that's milliseconds comparing to nanoseconds on instantiations.

On lines of code: that depends on formatting, but I agree that the difference is insignificant. Oh... I just realized, the difference is really insignificant. Emmm... Shame on me. Sorry for wasting your time.

@yarulan thank you, also for using Vavr. We will make it better — step by step...

Was this page helpful?
0 / 5 - 0 ratings

Related issues

liviamoroianu picture liviamoroianu  路  3Comments

skestle picture skestle  路  3Comments

roookeee picture roookeee  路  5Comments

Pyeroh picture Pyeroh  路  3Comments

civitz picture civitz  路  6Comments