Just published this blog on Hoplite <http://dev.to...
# feed
s
d
It looks very nice, but is there a separate artifact for Arrow support? So that those that don't use it, will not end up having a big dependency they don't use...
s
It’s built using arrow itself, so it would be pulled in regardless
d
Fine, but in Gradle, you could probably limit it, since otherwise people will end up with tons of extra classes...
s
limit it how ?
l
api
vs
implementation
probably
d
right!
s
But you need it on the classpath for hoplite to work
so either way it’s getting put into your final jar
d
The idea is that people won't understand `Monad`s etc... and will think that they are part of the standard library or something... even if the classes are in the jar, the IDE's autocomplete won't get flooded...
s
oh ok
but if I use implementation will it still be added to your build transitivity ?
d
Probably, only compileOnly will just use the dep in compile time... but then I'm no Gradle expert...
s
I’m not so sure because ultimately it ends up as a pom in maven central
and maven has no concept of this
i
@sam pom dependencies can have
runtime
scope, so it should be possible to represent the same concept in maven.
s
runtime means that it’s required at runtime but not at compilation time.
The library uses Arrow to represent errors internally as
Validated
along with other uses. So it’s needed to both compile, and to run. It’s not possible to ship this without arrow as you need arrow to run it but… I’d be open to copying the source files into the project itself and removing the dependency. It would only be 3 or 4.
👍🏼 1
i
runtime means that it’s required at runtime but not at compilation time.
I believe that's how Gradle's
implementation
dependency configuration should be mapped onto the Maven dependency scope. Maven pom produced from Gradle build describes how to consume the library, and not how to build it.
s
If
implementation
compiles with the dependency and then puts runtime into the pom, when someone adds it to their build it will throw a class not found exception if they don’t also add the required classes. So what’s the advantage? They ultimately need to add the dependency anyway.
i
Ok, if you expose Arrow types in your public API, then you definitely depend on it as
api
. We're talking about the situation when you don't expose them, which seems not to be the case here.
j
I really need a marketing course lol. I wish I could do thsi for my library 😄
s
Even if they’re not in the public api, but used by the internal code, you still need the dependency, so I think either way it’s going to be
api
. I’d be open to shading the dependencies though as it’s only a few files. That’s probably a better solution than requiring everyone to have arrow if that’s not what they want.
l
I don't really get all the anger towards bringing a dependency in... So many libraries bring so much inside them, and we usually never even see them. "They'll think Monad is in the STDLib" that doesn't happen for any class that comes bundled in any library I have ever used
When creating a UberJar or an APK, unused classes are removed anyway
People will never think "Oh, they added this class to the STDLIB". I just tested the monad example because I didn't even know I had Arrow on my classpath
s
I tend to agree, but I am also sensitive to the fact people may not want a dependency that does kind of “pollute” the namespace (for want of a better term)
l
It does pollute the name space, but we don't usually complain about it
s
But it’s clear why some people may not want that.
l
I agree, and I understand the pollution issue. Mainly in Arrow, that usually has everything on the
Any
namespace
If it's trivial to shadow the dependency or split the artifacts, you should go for it
But if it's not that easy, Maybe there are ways around it
j
I tend to think that a library as core as a configuration library should not bring many libraries as it might be used by small programs. Then you can have all the extras that you want, but not fore the "core".
👍🏼 2
l
That's a good point
s
Yeah I agree 100%. I’ll move the arrow
Decoder
instances to hoplite-arrow, and then shade the files the library uses. Thanks to @jdiaz @dave08 @ilya.gorbunov @LeoColman for the feedback
👍🏼 1
b
IIRC when they presented the idea of
api
vs
implementation
back at KotlinConf 2017 was implementation was meant to remove autocompletion of transitive dependencies that were purely
implementation
details whereas
api
was for dependencies exposed by your public API
l
Is that implemented?
g
Yes, it’s supported by Gradle Tooling, you have only classes exposed as API, not Implementation, this is the whole point of different dependency configuraions
So many libraries bring so much inside them, and we usually never even see them
You do, and even worse, you sometimes use it, but only because some library leaked implementation details, it;’s the same as use public everywhere
s
I don't understand this at all. If I have a class that I use internally in an API, lets say
com.google.wibble.Foo
whether it's
implementation
or
api
, that class must be present on the classpath at runtime. So what exactly is this difference giving me ?
g
DIfference is that user of your library can use this com.google.wibble.Foo too now, so essentially it because API of your library. Now you replaced it with
com.acme.wibble.Bar
in new version and it broke everyone who used it With
implementation
user of your library knows nothing about
com.google.wibble.Foo
, it’s runtime dependency
s
What is a runtime dependency ?
It's on the classpath regardless
g
it means that it can be used on runtime, but cannot be used during compilation of your client library
s
Ok, so this is some gradle magic that enforces this ?
s
Ok so whn this library is deployed to maven central, like 99% of libraries, that magic is going away
g
Parially Gradle, partially Maven POM
s
as Maven has no concept of it
g
like 99% of libraries, that magic is going away
No
s
Ok explain please 🙂
g
Maven also have concept of scopes for dependencies and it encoded in POM ffile
s
runtime, compile, etc
none of which are "use only for this project"
g
no, this is exactly what is runtime in POM
This scope indicates that the dependency is not required for compilation, but is for execution. It is in the runtime and test classpaths, but not the compile classpath.
s
runtime This scope indicates that the dependency is not required for compilation, but is for execution. It is in the runtime and test classpaths, but not the compile classpath.
g
so?
s
lets work through it
So I release a library. It has a single class,
class Foo { private val wibble = com.other.Wibble() }
Wibble is in a dependency of my project
if I set the dependency to runtime in the pom of my project, when someone adds it
g
if you add a library which has
runtime
transitive dependency, user of this library cannot use this dependency
s
but it's needed at runtime !
And maven will not add it !
g
yes!
will add
s
Will it
g
Yes
s
So a runtime dependency in my pom, means maven will add it to the path for execution but not to compile other projects
And you're sure that such a runtime dependency is also carried through transitivity to dependent projects
g
yes
s
So I'm wrong 🙂
g
Also yes. I use this for a couple years for JVM and Android starting from Gradle 3.4 where it was introduced I recommend to read java-library plugin documentation it has nice explanations about this feature: https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_separation
s
I've used maven for 15 years. I guess I've still got stuff to learn.
g
But want to add that you right, if you expose any type from your dependency in your public API you have to use `api`/`compilation` configurations
s
I've set the arrow deps and others to implementation now https://github.com/sksamuel/hoplite/commit/e6c59cc5950ad051dac49590358e94371664ecab
g
Why do you use compile and api together? you need only
api
, which mostly the same as
compile
s
because like you say isn't api the same as compile
g
yes, the same. This is why compile will be eventually deprecated (it’s already “soft” deprecated)