https://kotlinlang.org logo
Join the conversationJoin Slack
Channels
100daysofcode
100daysofkotlin
100daysofkotlin-2021
advent-of-code
aem
ai
alexa
algeria
algolialibraries
amsterdam
android
android-architecture
android-databinding
android-studio
androidgithubprojects
androidthings
androidx
androidx-xprocessing
anime
anko
announcements
apollo-kotlin
appintro
arabic
argentina
arkenv
arksemdevteam
armenia
arrow
arrow-contributors
arrow-meta
ass
atlanta
atm17
atrium
austin
australia
austria
awesome-kotlin
ballast
bangladesh
barcelona
bayarea
bazel
beepiz-libraries
belgium
berlin
big-data
books
boston
brazil
brikk
budapest
build
build-tools
bulgaria
bydgoszcz
cambodia
canada
carrat
carrat-dev
carrat-feed
chicago
chile
china
chucker
cincinnati-user-group
cli
clikt
cloudfoundry
cn
cobalt
code-coverage
codeforces
codemash-precompiler
codereview
codingame
codingconventions
coimbatore
collaborations
colombia
colorado
communities
competitive-programming
competitivecoding
compiler
compose
compose-android
compose-desktop
compose-hiring
compose-ios
compose-mp
compose-ui-showcase
compose-wear
compose-web
connect-audit-events
corda
cork
coroutines
couchbase
coursera
croatia
cryptography
cscenter-course-2016
cucumber-bdd
cyprus
czech
dagger
data2viz
databinding
datascience
dckotlin
debugging
decompose
decouple
denmark
deprecated
detekt
detekt-hint
dev-core
dfw
docs-revamped
dokka
domain-driven-design
doodle
dsl
dublin
dutch
eap
eclipse
ecuador
edinburgh
education
effective-kotlin
effectivekotlin
emacs
embedded-kotlin
estatik
event21-community-content
events
exposed
failgood
fb-internal-demo
feed
firebase
flow
fluid-libraries
forkhandles
forum
fosdem
fp-in-kotlin
framework-elide
freenode
french
fritz2
fuchsia
functional
funktionale
gamedev
ge-kotlin
general-advice
georgia
geospatial
german-lang
getting-started
github-workflows-kt
glance
godot-kotlin
google-io
gradle
graphic
graphkool
graphql
graphql-kotlin
graviton-browser
greece
grpc
gsoc
gui
hackathons
hacktoberfest
hamburg
hamkrest
helios
helsinki
hexagon
hibernate
hikari-cp
hire-me
hiring
hongkong
hoplite
http4k
hungary
hyderabad
image-processing
india
indonesia
inkremental
intellij
intellij-plugins
intellij-tricks
internships
introduce-yourself
io
ios
iran
israel
istanbulcoders
italian
jackson-kotlin
jadx
japanese
jasync-sql
java-to-kotlin-refactoring
javadevelopers
javafx
javalin
javascript
jdbi
jhipster-kotlin
jobsworldwide
jpa
jshdq
juul-libraries
jvm-ir-backend-feedback
jxadapter
k2-early-adopters
kaal
kafka
kakao
kalasim
kapt
karachi
karg
karlsruhe
kash_shell
kaskade
kbuild
kdbc
kgen-doc-tools
kgraphql
kinta
klaxon
klock
kloudformation
kmdc
kmm-español
kmongo
knbt
knote
koalaql
koans
kobalt
kobweb
kodein
kodex
kohesive
koin
koin-dev
komapper
kondor-json
kong
kontent
kontributors
korau
korean
korge
korim
korio
korlibs
korte
kotest
kotest-contributors
kotless
kotlick
kotlin-asia
kotlin-beam
kotlin-by-example
kotlin-csv
kotlin-data-storage
kotlin-foundation
kotlin-fuel
kotlin-in-action
kotlin-inject
kotlin-latam
kotlin-logging
kotlin-multiplatform-contest
kotlin-mumbai
kotlin-native
kotlin-pakistan
kotlin-plugin
kotlin-pune
kotlin-roadmap
kotlin-samples
kotlin-sap
kotlin-serbia
kotlin-spark
kotlin-szeged
kotlin-website
kotlinacademy
kotlinbot
kotlinconf
kotlindl
kotlinforbeginners
kotlingforbeginners
kotlinlondon
kotlinmad
kotlinprogrammers
kotlinsu
kotlintest
kotlintest-devs
kotlintlv
kotlinultimatechallenge
kotlinx-datetime
kotlinx-files
kotlinx-html
kotrix
kotson
kovenant
kprompt
kraph
krawler
kroto-plus
ksp
ktcc
ktfmt
ktlint
ktor
ktp
kubed
kug-leads
kug-torino
kvision
kweb
lambdaworld_cadiz
lanark
language-evolution
language-proposals
latvia
leakcanary
leedskotlinusergroup
lets-have-fun
libgdx
libkgd
library-development
linkeddata
lithuania
london
losangeles
lottie
love
lychee
macedonia
machinelearningbawas
madrid
malaysia
mathematics
meetkotlin
memes
meta
metro-detroit
mexico
miami
micronaut
minnesota
minutest
mirror
mockk
moko
moldova
monsterpuzzle
montreal
moonbean
morocco
motionlayout
mpapt
mu
multiplatform
mumbai
munich
mvikotlin
mvrx
myndocs-oauth2-server
naming
navigation-architecture-component
nepal
new-mexico
new-zealand
newname
nigeria
nodejs
norway
npm-publish
nyc
oceania
ohio-kotlin-users
oldenburg
oolong
opensource
orbit-mvi
osgi
otpisani
package-search
pakistan
panamá
pattern-matching
pbandk
pdx
peru
philippines
phoenix
pinoy
pocketgitclient
polish
popkorn
portugal
practical-functional-programming
proguard
prozis-android-backup
pyhsikal
python
python-contributors
quasar
random
re
react
reaktive
realm
realworldkotlin
reductor
reduks
redux
redux-kotlin
refactoring-to-kotlin
reflect
refreshversions
reports
result
rethink
revolver
rhein-main
rocksdb
romania
room
rpi-pico
rsocket
russian
russian_feed
russian-kotlinasfirst
rx
rxjava
san-diego
science
scotland
scrcast
scrimage
script
scripting
seattle
serialization
server
sg-user-group
singapore
skia-wasm-interop-temp
skrape-it
slovak
snake
sofl-user-group
southafrica
spacemacs
spain
spanish
speaking
spek
spin
splitties
spotify-mobius
spring
spring-security
squarelibraries
stackoverflow
stacks
stayhungrystayfoolish
stdlib
stlouis
strife-discord-lib
strikt
students
stuttgart
sudan
swagger-gradle-codegen
swarm
sweden
swing
swiss-user-group
switzerland
talking-kotlin
tallinn
tampa
teamcity
tegal
tempe
tensorflow
terminal
test
testing
testtestest
texas
tgbotapi
thailand
tornadofx
touchlab-tools
training
tricity-kotlin-user-group
trójmiasto
truth
tunisia
turkey
turkiye
twitter-feed
uae
udacityindia
uk
ukrainian
uniflow
unkonf
uruguay
utah
uuid
vancouver
vankotlin
vertx
videos
vienna
vietnam
vim
vkug
vuejs
web-mpp
webassembly
webrtc
wimix_sentry
wwdc
zircon
Powered by Linen
arrow
  • j

    jimn

    10/30/2019, 6:21 AM
    it's just an import oversight, right?
    r
    • 2
    • 1
  • j

    jimn

    10/30/2019, 6:41 AM
    as i try to match what i know to Arrow, it keeps recurring to me that i might be wasting my time if i want kotlin-mpp, though "pure" functional code and idioms is definitely a good thing to have. but knowing this, and settling for JVM to get work done, does arrow make a good intro to native languages mentioned in here that are purportedly more productive?
    r
    • 2
    • 5
  • j

    jimn

    10/30/2019, 7:36 AM
    since im at the bottom of the planet my daylight happens while everyone sleeps. but that said, I watched and annotated the july 11 arrowfx talk - my comments linked here.

    https://www.youtube.com/watch?v=uyqqoooKpmI&lc=UgxYVFk4CGJ389AAx2J4AaABAg▾

    😴 1
    r
    • 2
    • 5
  • a

    Attila Domokos

    11/03/2019, 3:42 AM
    Thanks for the response, @pakoito. Is there a blog post, tutorial, doc I could see how
    Either.catch
    looks like in this context? I understand
    Try { }
    is essentially the same, but it still reads better than
    try/catch
    .
    p
    • 2
    • 2
  • d

    Devesh Shetty

    11/03/2019, 6:11 AM
    Hello team, Is there any particular reason
    lose
    was not added to Decidable? https://hackage.haskell.org/package/contravariant-1.4.1/docs/Data-Functor-Contravariant-Divisible.html#v:lose https://github.com/arrow-kt/arrow/blob/master/modules/core/arrow-core-data/src/main/kotlin/arrow/typeclasses/Decidable.kt
    j
    • 2
    • 2
  • r

    raulraja

    11/03/2019, 10:59 AM
    You may have already seen that
    Try
    is deprecated in favor of IO and suspend. Changes like this are coming to other data types to eliminate nesting and improve ergonomics. Once Arrow Meta is available if you choose to use it you can entirely eliminate
    Either
    and all result types in Kotlin of Arbitrary arity. We are working on a plugin for Arrow Meta for Union Types. These union types are Coproducts of arbitrary arity that can be used without nesting:
    @optics
    @recursion
    typealias Result<A> = Union<Error, A> // Union<A, B, ...> synthetic and of arbitrary arity up to 22
    
    val a: Result<Int> = error //ok, no need to error.left()
    val b: Result<Int> = 1 // ok, no need to 1.right()
    val c: Int? = a // ok because it's an error becomes `null`
    val d: Int? = b // ok because it's an Int and stays Int
    val e: Result<Int> = "other type" // not ok because not an error or an Int. String is not part of the union
    
    val exhaustiveChecks = 
      when (a) {
        is Error -> TODO()
        is Int -> TODO()
      }
    
    a.fold({ e: Error -> TODO() }, { n: Int -> TODO() }) //@recursion folds cata and recursion schemes
    
    Result.error.msg.modify(a, String::trim) // @optics DSLs for all union and products
    As you can see in the example above there is no notion of left/right constructors and the datatype type args won’t be constrained to
    2
    . This also removes the need to use ADTs or sealed classes when your intention is just representing a disjoint union with types you don’t own or can’t modify. Additionally it will include a leaner runtime than Arrow Either or Arrow Coproduct because we can use the type checker in meta at compile time to determine when values are of the union and avoid allocation with unnecessary wrapping
    p
    • 2
    • 1
  • t

    tschuchort

    11/03/2019, 12:00 PM
    Looking forward to the union types. But the semantics of Validated are different than that of Either, so how can Union replace both?
    r
    • 2
    • 1
  • j

    Jannis

    11/03/2019, 1:04 PM
    How will typeclasses work with such unions? Based on the name or based on representation? Or not at all?
    r
    • 2
    • 6
  • j

    julian

    11/06/2019, 2:53 PM
    If Option reifies (is that the correct term?) the presence or absence of a value, is there a data type whose value is always present?
    p
    • 2
    • 2
  • k

    kluck

    11/06/2019, 2:55 PM
    @pakoito You were right, for my tests, I had kotlintest pulling arrow in version 0.9.0. I excluded it in gradle and it then worked correctly. On the other hand, I couldn't find any other dependency problem for then android app part. What I found is that it doesn't work on one of my device (and android 5) but does on another (android 8 ). This
    arrow.fx.internal.Platform$_trampoline$1
    really seems
    Platform
    -related after all... Any thoughts?
    p
    a
    • 3
    • 11
  • t

    tmg

    11/07/2019, 3:02 PM
    I would say hat has more to do with Strongly Static Typed FP and it's advanced. The most important parts are composition, immutability. and avoiding side-effects.
    💯 1
    j
    p
    • 3
    • 12
  • s

    simon.vergauwen

    11/08/2019, 2:50 PM
    That’ll be fixed with Arrow Meta but for now you got to either separate into 2 modules or, add the HKT boilerplate yourself.
    class ForResult private constructor() { companion object }
    typealias ResultOf<A> = arrow.Kind<ForResult, A>
    
    @Suppress("UNCHECKED_CAST", "NOTHING_TO_INLINE")
    inline fun <A> ResultOf<A>.fix(): Result<A> = this as Result<A>
    👍 1
    k
    • 2
    • 1
  • r

    Ryan Benasutti

    11/08/2019, 4:40 PM
    Does Arrow have a way to repeatedly run a predicate to monitor something, as a way to bridge into the async stuff, which expects suspending functions? I am imagining that the predicate would return true when the async computation has finished (be it success or failure), at which point arrow should call the correct callback.
    p
    • 2
    • 3
  • p

    pakoito

    11/08/2019, 5:17 PM
    you
    race
    with an
    IO.sleep
    🔝 1
    r
    • 2
    • 2
  • j

    julian

    11/08/2019, 6:42 PM
    Is there anything that out there that charts a path through FP with Arrow from newbie to mastery as a working developer? Something like this http://lambdaconf.us/downloads/documents/lambdaconf_slfp.pdf. But not so bare bone.
    m
    j
    • 3
    • 3
  • m

    Miguel Coleto

    11/08/2019, 8:15 PM
    I think there is a repository porting every example from that book into Arrow
    😮 1
    👍🏾 2
    r
    j
    s
    • 4
    • 6
  • j

    julian

    11/09/2019, 7:13 PM
    @marc0der Not a shameless plug at all! I'm up to chapter 4 of the MEAP! 😄 I was so pleased when I found out this book was in the works, because I'd tried to work through the entirety of the Red Book (Functional Programming in Scala), doing all the problems, but got so bogged down at Chapter 7 (Purely Functional Parallelism) that I moved on to other books. This was largely, I think, because my cognitive processing was overloaded by having to juggle both understanding Scala syntax (completely new to me, at the time) and learning FP (also completely new, at the time). My familiarity with Kotlin has made the chapters of FPIK released so far a breeze. Thank you so much for writing this book! It is truly a gift to Kotlin FPers.
    👍 3
    p
    m
    +2
    • 5
    • 14
  • p

    pakoito

    11/10/2019, 7:09 PM
    that’s what’s available today
    z
    • 2
    • 1
  • p

    pakoito

    11/12/2019, 10:55 AM
    https://github.com/arrow-kt/arrow/issues/1789
    👌 1
    r
    p
    • 3
    • 9
  • g

    Greg Hibberd

    11/13/2019, 9:14 PM
    Hi guys, is there a nicer way of mutating single items in a list?
    fun ListK<Tuple2<String, Int>>.modifyListItem(key: String, amount: Int) = Option.fx {
            //Find the item
            val index = indexOfFirst { it.a == key }.let { if(it == -1) None else Some(it) }.bind()
            //Get the item
            val item = get(index)
            //Modify
            val modified = itemLens.set(item, item.b + amount)
            //Create an index
            val listIndex = ListK.index<Item>().index(index)
            //Replace the item
            listIndex.set(this@modifyListItem, modified)
    }
    j
    • 2
    • 2
  • p

    pakoito

    11/13/2019, 9:36 PM
    list.map {
      if (it.a == key) {
        ...
      } else {
        it
      }
    }
    g
    j
    • 3
    • 6
  • s

    Stian N

    11/14/2019, 10:30 AM
    The documentation for ListK seems to be missing in the current version
    r
    • 2
    • 5
  • p

    pakoito

    11/14/2019, 3:12 PM
    make sure that you aren't pulling 2 different versions of arrow
    t
    • 2
    • 1
  • p

    pakoito

    11/14/2019, 4:48 PM
    maybe @aballano has some idea here
    a
    t
    • 3
    • 9
  • n

    Nikita Smolenskii

    11/15/2019, 9:28 AM
    I have seen an article https://www.47deg.com/blog/arrow-v0-10-3-release/ and really corious about one particular thing:
    Either.catch
    that forces suspend. Article provides following code snippet, that somehow correate with current implementation https://github.com/arrow-kt/arrow/blob/b332574a969497dc9f072d52bbb5eea60081a9fe/modules/core/arrow-core-data/src/main/kotlin/arrow/core/Either.kt#L859
    suspend fun <A> Either.Companion.catch(f: suspend () -> A): Either<Throwable, A> =
    try { f().right() } catch (t: Throwable) { t.left() }
    Is there any particular reason to not do instead, that allow
    catch
    function to be
    suspend
    agnostic
    inline fun <A> Either.Companion.catch(f: () -> A): Either<Throwable, A> =
    try { f().right() } catch (t: Throwable) { t.left() }
    with that decalration, both will be possible, with initial declaration - second one only
    fun blocking(): Int = 42
    suspend fun suspended(): Int = 42
    
    fun main() {
        Either.catch { "first: ${blocking()}" }
        
        runBlocking {
            Either.catch { "second: ${suspended()}" }
        }
    }
    Why arrow team forces to use coroutines everywhere? Even if it’s not needed.
    k
    s
    • 3
    • 2
  • j

    Jannis

    11/15/2019, 9:32 AM
    From the article: "Try can never yield pure functions since it’s eager and executes the effects on construction; it can only be made pure by marking it as suspend." Suspend marks side effects, and throwing exceptions, the whole purpose of code run in catch, is a side effect.
    ☝️ 1
    n
    k
    • 3
    • 13
  • a

    abendt

    11/15/2019, 7:29 PM
    hi folks, i am currently trying to learn more about functional programming and arrow. as an exercise and inspired by https://github.com/arrow-kt/arrow/issues/1747 i tried to implement the semialign typeclass with instances for some arrow types (Id, Option, ListK, MapK, Nel, SequenceK). would there be interest for a PR? i would definitely need some guidance and review around the implementation.
    j
    • 2
    • 4
  • j

    Jannis

    11/15/2019, 7:32 PM
    Yes definitly 👍 Just go straight ahead with it, and if you have questions just ask 🙂
    👍🏾 1
    a
    • 2
    • 1
  • j

    Johan Basson

    11/16/2019, 6:40 AM
    Hi I'm trying to understand and use the Reader Monad, but i'm stuck trying to use it in a function This is my current function:
    fun authenticate(
        request: AuthenticateRequest,
        secretKey: SecretKey,
        con: Connection
    ): Either<ErrorMessage, Token>> = Either.fx {
        val (optUser) = getUserByUsername(con, request.username)
        val (user) = checkUserExists(optUser)
        val (_) = checkPassword(request.password, user)
        val (token) = generateToken(user, secretKey)
        token
    }
    In this case secretKey and Connection is dependencies From what I understand you can use the Reader monad to inject it from the top of the application:
    fun authenticate(request: AuthenticateRequest): Reader<Context, Either<ErrorMessage, Token>> {
        return ReaderApi.ask<Context>().map { ctx ->
            Either.fx {
                val (optUser) = getUserByUsername(ctx.sql2o, request.username)
                val (user) = checkUserExists(optUser)
                val (_) = checkPassword(request.password, user)
                val (token) = generateToken(user, ctx.secretKey)
                token
            }
        }
    }
    But this does not seem to compile
    s
    • 2
    • 1
  • j

    Jannis

    11/17/2019, 7:44 AM
    Btw the quoted text is not 100% accurate: Try can yield pure functions, just not any useful ones. Try with pure functions is itself pure, it will just always succeed and thus not be useful at all 😉
    s
    • 2
    • 111
Powered by Linen
Title
j

Jannis

11/17/2019, 7:44 AM
Btw the quoted text is not 100% accurate: Try can yield pure functions, just not any useful ones. Try with pure functions is itself pure, it will just always succeed and thus not be useful at all 😉
s

sam

11/20/2019, 2:34 AM
What about
Try { "a".toInt() }
j

Jannis

11/20/2019, 11:21 AM
"a".toInt()
has the type
fun String.toInt(): Int
which would mean it would have to be defined for all strings possible. But it isn't as not all strings can be converted to ints. Thats a partial function and partial functions throw exceptions on unhandled input and are thus not pure. Throwing an exception is an action not indicated by the return type => definition of a side effect.
fun Sring.toInt(): Int
is much better if it has either
Option<Int>
or
Either<SomeDescriptiveError, Int>
(or similar) as a return type. Coming back to
Try
since
String.toString(): Int
is impure and
Try
does not suspend that side effect, the invocation of
Try
is by definition also impure.
But also: This use of
Try
is the main purpose it was added for (as a simple wrapper around try catch), so using it that way is also not too bad when no other side-effects are involved. It's just that kotlin cannot prove that with it's type system, making this a bad abstraction because it's too easy to use it wrong. I usually follow two paths when working with exception throwing functions that I have no control over: Wrap it in suspend because it might be doing side-effects or use try catch directly and convert to option/either for code that I know is otherwise pure. It's quite useful to define an extension function for that. The only reason arrow does not provide this is because it's again, like
Try
, an abstraction that promotes misuse and we try to avoid that in arrow.
s

sam

11/20/2019, 6:00 PM
I disagree 🙂 A pure function is one that returns the same outputs for the same inputs, and doesn’t have side effects. Parsing a string into an int and returning a
Try
value is such a function. I don’t believe there’s any requirement for the function to be total. The reason I asked about this is because when people question why
Try
was deprecated, I think the better answer is not “because it’s not pure” but because “we don’t want to encourage people to catch IO exceptions” or “we don’t want to encourage strict evaluation of effects”.
j

Jannis

11/20/2019, 8:19 PM
Totality is required for pure functions as they otherwise would not be pure (they will throw on undefined input that makes them impure). And yes
fun a(str: String) = Try { str.toInt() }
is total and deterministic and thus anything returning
Try
is pure (if and only if there are no other side-effects apart from exceptions). That is not the problem with
Try
though. The problem is anything within it has to be impure to be useful, and that is not what arrow wants to promote. As I said in my second message, wrapping impure code that has no other side effects and that you have no control over, is exactly what
Try
is/was useful for and that's still how I use it (or an equivalent ext func to option or either). But as the deprecation message states: Try promotes use of impure functions (or something like that) and that is just bad in all cases. My original message is indeed wrong.
Try
is pure in all cases that only involve non-fatal exceptions (fatal exceptions are rethrown afaik). So a good answer to "why is
Try
deprecated?" is: "Because it promotes using and writing impure functions". The other part about IO or effects is also true, but not the only reason.
Sadly most libraries writting for the jvm world have an impure api, so to wrap it you either need
IO
or
Try
(or equivalent). If you know it has no side-effects other than exceptions (which is quite hard to figure out about code you do not own) then
Try
is perfectly fine, for all other cases use
IO
or equivalently suspend
s

sam

11/20/2019, 8:23 PM
I’d be interested as to why you think it has to be total to be pure, I couldn’t find literature to back that up. In general I agree with you about Try I just think the deprecation reasons could be better communicated by taking about IO
j

Jannis

11/20/2019, 8:23 PM
Because a non-total function throws on input it is not defined for
and throwing is a side effect => impure
s

sam

11/20/2019, 8:24 PM
Is it
j

Jannis

11/20/2019, 8:24 PM
Any observable state change outside of what the return type indicates is considered a side effect
s

sam

11/20/2019, 8:24 PM
You could argue that throwing an exception is a return type of sorts
j

Jannis

11/20/2019, 8:24 PM
and exceptions change state quite a bit by aborting computation
s

sam

11/20/2019, 8:25 PM
I don’t like exceptions anymore than you, I just think
a.toInt()
fulfils the rules of purity - output is always the same for the input and it has no side effects.
j

Jannis

11/20/2019, 8:26 PM
not strictly:
fun String.toInt(): Int
has no indication that it might throw, similar to
fun Int.div(i: Int): Int
both are lying signatures. You should be able to read it as: "for all strings I will get an Int"
but thats not true!
s

sam

11/20/2019, 8:26 PM
public Int toInt(String input) throws NumberFormatException
is that better ?
j

Jannis

11/20/2019, 8:27 PM
yes, in terms of return type it is, now it's a union of
Int | NumberFormatException
. It has lots of other problems but it is something I'd consider pure
s

sam

11/20/2019, 8:28 PM
The kotlin one is the same, it’s just not as obvious. My point wasn’t “throwing exceptions is sometimes ok”, it’s just that these examples are pure even if they’re poor examples of code style
The JDK should just return an Optional<Int> or whatever
j

Jannis

11/20/2019, 8:29 PM
wait where is the kotlin one the same? o.O
s

sam

11/20/2019, 8:29 PM
fun String.toInt(): Int
<-- it’s the same just the exception isn’t included in the return type, but it’s the same as the Java one.
j

Jannis

11/20/2019, 8:30 PM
Well yeah, might call the same function, but as long as the exception is not included in the type it is worse 🙂
s

sam

11/20/2019, 8:30 PM
It’s exactly the same as the Java one that you said is now ok because it’s a union. The Kotlin one is a union too. It’s awful, but pure.
j

Jannis

11/20/2019, 8:31 PM
Wait it does not mention the exception, why would that be the same?
s

sam

11/20/2019, 8:31 PM
We know the exception can be thrown.
j

Jannis

11/20/2019, 8:31 PM
From what?
Where does this knowledge come from? Not from the type
s

sam

11/20/2019, 8:32 PM
20 years of using it.
j

Jannis

11/20/2019, 8:33 PM
That sadly does not make it equivalent to the signature with
throws NumberFormatException
. It needs to be in the signature/return type to be considered pure
s

sam

11/20/2019, 8:33 PM
If you want to say that having possible errors encoded explicitly in the return type is a good thing. I agree. 100%. That’s why I always use functional error handling.
💯 1
So languages that do not declare the return type cannot be pure ?
const foo = (a) => a + 1
Is that pure
j

Jannis

11/20/2019, 8:34 PM
Hmm, yes and define is the wrong word to use as that example shows 🙈 Haskell can be untyped yet is pure for example.
s

sam

11/20/2019, 8:35 PM
So it doesn’t need to be in the signature/return type ?
So if you agree it doesn’t need to be in the signature, then the kotlin one can be pure
j

Jannis

11/20/2019, 8:36 PM
Yes and no, if the infered type matches what the correct return type would be fine! If you define
fun String.toInt() = toInt()
it's just as impure
s

sam

11/20/2019, 8:36 PM
It’s only impure if you’re going to define throwing an exception as impure
j

Jannis

11/20/2019, 8:36 PM
A throwing function cannot be pure unless the return type indicates it wether you specify it or not. If you let the compiler infer it it still has a return type
s

sam

11/20/2019, 8:37 PM
Not all languages have inferred types.
The only rules for purity that I can find are no side effects and output based only on input.
So that’s my original point. We’re better off saying “don’t use try because exceptions tend to hide bad things”
Let’s not say that every function that throws is necessarily impure even if they usually are
j

Jannis

11/20/2019, 8:38 PM
and the definition of side effect is "no state-change outside of what is indicated by the return type"
that is where throwing becomes impure
s

sam

11/20/2019, 8:39 PM
It’s just a value that’s passed around in a special way. It’s getting a bit picky otherwise.
j

Jannis

11/20/2019, 8:39 PM
What is? Exceptions?
s

sam

11/20/2019, 8:40 PM
Yeah
j

Jannis

11/20/2019, 8:40 PM
They break control flow and are not in the return type. They are quite a big deal imo
s

sam

11/20/2019, 8:40 PM
I agree they are a big deal and generally avoided !
As I’ve been saying
j

Jannis

11/20/2019, 8:40 PM
If I define
fun a(arg: A): B
I do not want this to throw ever
s

sam

11/20/2019, 8:40 PM
agreed
j

Jannis

11/20/2019, 8:41 PM
And by definition it should never in a pure setting
s

sam

11/20/2019, 8:41 PM
But if you have an existing awful function like .toInt that does throw, wrapping it in a Try makes it pure, even if it’s still shit
j

Jannis

11/20/2019, 8:41 PM
If you cannot change it, then yes. and as I said previously sadly there is lots of those out there 🙂
s

sam

11/20/2019, 8:41 PM
Do you agree that the real reason we’re saying avoid
Try
and things like that is because they tend to hide effects
j

Jannis

11/20/2019, 8:42 PM
Thats part of it
But also that it promotes using it on own code that throws
s

sam

11/20/2019, 8:42 PM
That’s a fair point.
The purity angle is not the one to use though. Let’s use those two points - Don’t use Try because it encourages the use of strict effects and because it promotes using code that throws
In other news, when are you going to merge propcheck into KotlinTest so we can have all the goodies 😂
j

Jannis

11/20/2019, 8:44 PM
Well
Try
is pure, code that is useful to use inside
Try
and has no other side effects is not. Btw thanks for pointing out that
Try
is pure, I had that wrong first. 🙂
I am currently playing around with integrated shrinking, if I can get a nice api for it I'll rethink it. But there are a few problems
not with the approach itself but with what it implies on writing tests
s

sam

11/20/2019, 8:46 PM
You want to be able to generate shrinkers ?
j

Jannis

11/20/2019, 8:46 PM
No and yes
s

sam

11/20/2019, 8:46 PM
lol
j

Jannis

11/20/2019, 8:46 PM
😄
whoops
one message at a time please slack
integrated shrinking is a concept where instead of generating a single value you generate a rose tree of values where the branches contain shrunk values
s

sam

11/20/2019, 8:47 PM
Well I’d love to get you contributing to KotlinTest on the property test stuff so if you ever fancy it let me know 🙂
What’s the advantage of that ?
j

Jannis

11/20/2019, 8:47 PM
The genius part of this approach (which the hedgehog library made popular) is that transformations to the value generated transforms all shrunk values as well
That means it retains invariants
s

sam

11/20/2019, 8:48 PM
That’s a nice feature
And something that isn’t even supported in quickcheck or scalacheck I don’t think ?
j

Jannis

11/20/2019, 8:48 PM
Also you never have to write custom shrinkers
Scalacheck has a smaller feature set than quickcheck and quickcheck cannot have that
different approaches to shrinking
It has some drawbacks tho, even apart from it having some implications on writing tests and generators
s

sam

11/20/2019, 8:51 PM
I will monitor your project, I saw your ticket for this
j

Jannis

11/20/2019, 8:51 PM
for example:
val genA = Gen.fx {
  val length = int(0..100).bind()
  string().list(length)
}
this is a perfectly fine generator for creating lists strings, however when shrinking it will first shrink the length and then the elements inside the list. That means once it shrunk the content list it cannot go back to shrinking the length
That is very obvious when shrinking tuples, but there are solutions to that, those are just not as nice
s

sam

11/20/2019, 8:53 PM
Yeah I’ve ran into the issues when trying to apply a shrinker to a user’s map function
Gen.ints().map { … }
j

Jannis

11/20/2019, 8:53 PM
yes I saw the ticket discussing that ^^
But that is also for a different reason, mapping over gens with rose trees is perfectly fine
it's just monad operations like flatMap that fail
s

sam

11/20/2019, 8:55 PM
I’ll have to read up rose trees and how they would solve the mapping problem
j

Jannis

11/20/2019, 8:55 PM
Because in
flatMap
the result is a function, so to shrink it it has to first evaluate it, but you cannot go back after doing so
rose tree's on their own are just:
class Rose<A>(val el: A, val branches: Sequence<Rose<A>>)
Getting them to work nicely with a decent api is quite a bit of work tho.
s

sam

11/20/2019, 8:59 PM
So it’s just a n-tree where each node has a value ?
j

Jannis

11/20/2019, 8:59 PM
Yes, and in terms of shrinking every branch represents a shrunk value with the first one being the smallest one and n + 1 being larger than n
s

sam

11/20/2019, 9:00 PM
Right
So it’s easy to locate the shrunk value for any given n
j

Jannis

11/20/2019, 9:01 PM
For any element of a rose the shrunk values are the elements in the branches, and the branches are ordered smallest to largest
don't know if that is what you asked 😄
s

sam

11/20/2019, 9:02 PM
yes
that’s what I was saying, it’s a neat solution
👍🏻
j

Jannis

11/20/2019, 9:03 PM
Yes, but the drawbacks with
flatMap
require quite a bit of work to overcome. The solution is two fold: Don't ever use it unless you need it, and if you need it either ignore that you have worse shrinking or add you own shrinking back 😕
Have you seen how Hypothesis for python works?
It's yet another completly different attempt at shrinking and generating
s

sam

11/20/2019, 9:06 PM
No
I’ll add that to my reading list
j

Jannis

11/20/2019, 9:08 PM
Quick summary is: Instead of using a random gen, it flips a coin for every random choice and keeps track of the results. When shrinking it shrinks this list of coin flips based on heuristics. Seems to work good enough, but I have my doubts. It's an interesting solution though
s

sam

11/20/2019, 9:11 PM
clever for sure
View count: 3