Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

["Request"] Partial function application "invoke" no longer available #2693

Open
dmstocking opened this issue Mar 22, 2022 · 5 comments
Open

Comments

@dmstocking
Copy link

What version are you currently using?
Arrow Core 1.0.1

What would you like to see?
It looks like when the new git repository was made. partials.kt's invoke function was not brought over. I can't find an explanation as to why. So, I am not sure if this was an oversight or an intention choice. I am trying to do the same thing that #814 was trying to do. The proposed solution is no longer available though as of 1cd9a90#diff-c32792a648907577ba1b8c6f75dd29ceef90404be1348a501f8f136ef9e8681b. Was this on purpose? How do you partially apply multiple arguments besides just doing partial1(..) multiple times?

@nomisRev
Copy link
Member

Hey @dmstocking,

This was an intentional removal because it blows up the binary quite a lot, and it's typically not very useful in Kotlin.
Might I ask you what your use-case is?

Typically it's more straightforward to just create an anonymous lambda instead, and capture the values inside.

fun theFn(string1: String, string2: String, string3 : String) = string1 + string2 + string3
val partiallyApplied = { str: String -> theFn("Hello", "World", str) }

listOf("!", "?", ".").map(partiallyApplied)

or simply

listOf("!", "?", ".").map { theFn("Hello", "World", it) }

Not sure if your use case is different from this, but this typically results in more idiomatic Kotlin.
Additionally, Kotlin heavily optimizes lambdas so that this results in much nicer and optimized bytecode.

@dmstocking
Copy link
Author

dmstocking commented Mar 22, 2022

We were trying to build two variants of an object for testing. One needed a version that had a real dependency that used Netty and another was using an EmbeddedChannel, so that we didn't need to actually connect to something. Anyway the only difference between the two classes was a few arguments. So, I wanted to remove the duplicated code, and I actually used a lambda at one point. The problem though is it is a fairly big lambda. Anyway, let me show you how the changes went down.

Note that I changed some of the names so that they are shorter. Most of the real code has more descriptive names that force putting arguments on separate lines.

// the real connection
        val connection = Connection(
            ChannelFactory(eventLoopGroup, true, logger, Deserializer(), Serializer(), remote),
            logger,
        )
// vs the fake
        val connection = Connection(
            EmbeddedChannelFactory(true, logger, Deserializer(), Serializer(), remote),
            logger,
        )

The last 4 arguments are all the same. So, why not just make a function that creates those and you just pass the lambda on what you want to create? That is exactly what I did, but it turns into.

// the real connection
        val connection = createConnection { logger, deserializer, serializer, remote ->
            ChannelFactory(eventLoopGroup, true, logger, deserializer, serializer, remote)
        }
// vs the fake
        val connection = createConnection { logger, deserializer, serializer, remote ->
            EmbeddedChannelFactory(true, logger, deserializer, serializer, remote)
        }

With Partial Application, I could do.

// the real connection
        val connection = createConnection(::ChannelFactory(eventLoopGroup)(true))
// vs the fake
        val connection = createConnection(::EmbeddedChannelFactory(true))

Which I felt looked really nice and was easier to maintain.

@serras
Copy link
Member

serras commented Aug 9, 2022

@dmstocking are you still interested in pursuing this? Maybe we can find a nicer design which doesn't require tons of utility functions in the library.

@dmstocking
Copy link
Author

I would love some way to make this easier. I don't have any suggestions though. I haven't thought about this in a while. Was there any thoughts on how to do that? (I am sort of assuming you want to clear out old tickets if nothing is going to be done with them)

@nomisRev
Copy link
Member

nomisRev commented Aug 9, 2022

I think the best way forward to support such functionality, this includes all functionality such as partial application, currying, function composition, etc to be implemented through a Kotlin compiler plugin.

Such that you can add these functions in an n-arity way to the language. I don't see any other way of doing this in a typed way, without redeclaring all the different arities.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants