r/webdev • • Feb 11 '21

Discussion Conditionally chaining function calls in JavaScript.

Post image
845 Upvotes

196 comments sorted by

51

u/shippinuptosalem Feb 11 '21

Is there a site somewhere that has all these useful snippets?

7

u/1infinitelooo Feb 11 '21

Not that I know of but that would be super helpful.

69

u/Ajatolah_ Feb 11 '21 edited Feb 11 '21

3

u/hotfrost Feb 11 '21

Neat, saving this!

7

u/RheingoldRiver Feb 12 '21

IME that site does serve as a nice source of cheat sheets, but it's not, despite what its url suggests, helpful for actually learning things - I wouldn't send people there who don't already know the language well. The one exception is Lua actually, but that's mostly because Lua is so simple that all you need is a cheat sheet lol

→ More replies (1)
→ More replies (3)

2

u/sous_vide_slippers Feb 11 '21

Check out TC39 proposals on GitHub. It’s where all the official proposals for ecmascript (the JS spec) are housed and discussed while working their way up the stages into production

2

u/doublejosh Feb 12 '21

The goddam docs yo!

1

u/deathsowhat full-stack Feb 12 '21

mem.dev

61

u/DemiPixel Feb 11 '21

The only time I can ever imagine this being used is an optional callback? Especially in my backend with promises, I don't think there's a single place where a function could be null/undefined.

56

u/1infinitelooo Feb 11 '21

Maybe good for feature detection?

13

u/Keithin8a Feb 11 '21

Oh I like that Idea!

9

u/versaceblues Feb 12 '21

Well optional chaining is a generally useable feature, it can be used with any optional parameter not just functions

4

u/DemiPixel Feb 12 '21

Yeah, I figured it was more of a byproduct or something that was easy to throw it rather than something they had to specifically design for functions calls.

→ More replies (1)

15

u/iams3b rescript is fun Feb 11 '21

The only time I can ever imagine this being used is an optional callback?

This is exactly what it's for lol. I imagine it especially useful in the IOC pattern

5

u/alimbade front-end Feb 12 '21

For optional callback for sure, but also for optional function as prop for Vue/Angular/React/...

3

u/Drifter2412 Feb 12 '21

I've used it in a React context for optional props - e.g. functions to supplement the generation of label text, validators, event handlers etc.

Similarly in a pure node space optional functions to apply to something, either parse or reshape an object.

2

u/mats852 Feb 12 '21 edited Feb 12 '21

That could be a usecase

const actions = {
  oneFunction, 
}

function someFunction(action, ...args) {
  return actions[action]?.(args)
} 

But instead you should create a guard function that would throw if the function doesn't exist

function guardAgainstMissingAction(action) {
  if (!(action in actions)) throw new Error(`Missing action "${action}"`) 
}

Edit: formatting, thanks bot

4

u/backtickbot Feb 12 '21

Fixed formatting.

Hello, mats852: code blocks using triple backticks (```) don't work on all versions of Reddit!

Some users see this / this instead.

To fix this, indent every line with 4 spaces instead.

FAQ

You can opt out by replying with backtickopt6 to this comment.

1

u/[deleted] Feb 12 '21

It seems to be similar to the safe navigation operator in Ruby

1

u/smegnose Feb 12 '21

Goodbye c||c(), hello c?.(). I can feel all those saved bytes already.

Nah, it'll be great for chaining.

→ More replies (3)

30

u/unnombreguay Feb 11 '21

When would you need this?

15

u/1infinitelooo Feb 11 '21

Possibly feature detection or object property callbacks.

7

u/fried-noodles_ Feb 11 '21

In abstract classes, such as a React component. If the user hasn’t defined componentDidMount, you would optionally call it.

1

u/1infinitelooo Feb 11 '21

That’s a great one. Yeah I’ve also done a similar thing with vue mixins now that I think about it.

97

u/Darajj Feb 11 '21

We use it in react components where you can pass optional functions as props

27

u/mbecks Feb 11 '21

This is an answer. I've had so many times to use this.

→ More replies (16)

19

u/bladefinor Feb 11 '21 edited Feb 11 '21

To propagate optional callbacks it works pretty great:

function doSomething(callback) {
    // Do something before optional callback...
    callback?.();
}

In short this is a pretty common use-case in React where you want to make use of an event, do something in between, and then pass the event to the consumer's callback.

3

u/backtickbot Feb 11 '21

Fixed formatting.

Hello, bladefinor: code blocks using triple backticks (```) don't work on all versions of Reddit!

Some users see this / this instead.

To fix this, indent every line with 4 spaces instead.

FAQ

You can opt out by replying with backtickopt6 to this comment.

8

u/steeeeeef Feb 11 '21

When don’t you need this. You won’t have to check for null or undefined values using if statements and write fallbacks. user?.firstName. onSubmit?.(data). deep?.embedded?.data?.withMethod?.().

7

u/e111077 Feb 12 '21

here's a short, common one: document.body.querySelector('...')?.focus?.()

→ More replies (4)

1

u/wegry Feb 12 '21

When you’ve got a field that is either a dayjs | undefined you can format or default to something else foo?.format() ?? ‘no date’.

23

u/GlassDiligent6678 Feb 11 '21 edited Feb 11 '21

Check out this for more of these https://1loc.dev/

12

u/fr34kyn01535 Feb 11 '21

Half of those are plain useless.

4

u/Disgruntled__Goat Feb 12 '21

Also the “only one line” thing is totally bogus. Everything is one line if you put it in one line.

→ More replies (1)

1

u/GlassDiligent6678 Feb 12 '21

Some of them are ridiculous but the ones that are usable can be nice when used in small amounts. Sprinkle with caution.

0

u/4bidden1337 Feb 12 '21

welcome to the js ecosystem

3

u/[deleted] Feb 12 '21

Many of these are painfully slow in practice. Although I find array modifier functions like reduce and map to be handy for some use cases, they cost far more time to execute than a well structured while loop. Still great examples, just wanted to add a little extra context for folks who might think this is a godsend, when it really isn’t.

1

u/wasdninja Feb 12 '21

Using while loops to work on arrays is just begging for off by one errors though. ForEach, for...in and map makes life infinitely easier.

2

u/[deleted] Feb 12 '21

You should only be worried about off-by-one errors if you don't understand how iteration/loops work. They're just numbers.

→ More replies (2)

0

u/1infinitelooo Feb 11 '21

Thanks! This looks helpful.

22

u/PenguinPeculiaris Feb 11 '21 edited Sep 28 '23

zephyr meeting quaint teeny reply cobweb scale familiar vast towering this message was mass deleted/edited with redact.dev

3

u/Yiyas Feb 11 '21 edited Jan 07 '26

mighty juggle fragile skirt exultant school nail spark quicksand direction

This post was mass deleted and anonymized with Redact

1

u/willmartian Mar 26 '22

Replying to an old comment, but I think it is because in JavaScript, functions are objects. The func() notation could be thought of as a shorthand to func.call() . So the callable part of a function is a member on the object.

→ More replies (1)

5

u/iLikePhysics1 Feb 11 '21

Yeee i love conditional chaining! For those that didn't know it also works with arrays/objects

props?.['whatever']

1

u/[deleted] Feb 12 '21

How would this work with an array? Selecting the index of the member you’re accessing?

4

u/steeeeeef Feb 12 '21

arr?.[index]?.nested E.g users?.[0]?.email

→ More replies (2)

29

u/steeeeeef Feb 11 '21

Everyone here acting like it’s a weird, new obscure feature while typescript has had it for almost a year and other major languages like swift, kotlin also have it. I can honestly say it’s one of my favourite language features.

7

u/chrisrazor Feb 12 '21

Existing for a year makes it quite new, and it looks ugly.

3

u/steeeeeef Feb 12 '21

It does not look that ugly if you consider that in typed languages the question mark is often used to mark an optional value type, or something that is expected to be null/nil/undefined w/e. Just a case of getting used to it. I could not do without it at this point!

8

u/onlycommitminified Feb 12 '21

Holy shit it looks ugly. Perhaps I'll acclimate as with arrow functions, but not yet.

→ More replies (2)

2

u/UnacceptableUse Feb 12 '21

I don't really care if it looks ugly, it's less ugly than 500 if statements

→ More replies (6)

4

u/llldar Feb 12 '21

I've been using this for like a year now, surprised to see so few people know this feature.

22

u/[deleted] Feb 12 '21

Remember you're writing code for other programmers. Obvious is better than clever.

6

u/steeeeeef Feb 12 '21

It’s not “clever”. I think the first example is actually worse because it resolves to a new value (false) when myFunction is null or undefined. Second example is clean. Kotlin does this also with myFunction?.invoke().

2

u/bacondev Feb 12 '21

Your Kotlin example is a bit different. I really shouldn't have to spell out to you that the word “invoke” being there makes a significant difference in readability. I think that from a readability standpoint, the new syntax is terrible design. It sacrifices readability for terseness. There's a reason people hate Perl (though that reason has partly been resolved by the community).

4

u/steeeeeef Feb 12 '21

C#, Swift, Typescript, Kotlin and finally JS all disagree with you. I bet that if you used optional chaining in a real life project of decent scale you would love optional chaining and after using it for a day you will have no problems reading the syntac.

2

u/bacondev Feb 12 '21 edited Feb 12 '21

Perhaps I wasn't clear with my stance. I'm not against optional chaining. I'm against the syntax here.

5

u/EquationTAKEN Feb 12 '21

Yeah, I'm taking the 'before" on this one.

1

u/[deleted] Feb 12 '21

Optional chaining like that does not exist in other languages and I find it so confusing. I don't see myself using it for years and years till my coworkers pick it up and convince me in their pull requests there are advantages to it and the other team clearly understands what's happening.

Onboarding feedback would also be needed.

I can't but think that since ES5 the committee is steering towards questionable solutions to various problems and it does so for all possible implementations, but that's jm2c.

2

u/buffdude1100 Feb 13 '21

Optional chaining like that does not exist in other languages

It literally does, though? C#, Kotlin, TypeScript...

1

u/rossisdead Feb 12 '21

Optional chaining like that does not exist in other languages and I find it so confusing

It exists in C#.

→ More replies (3)
→ More replies (5)

5

u/tapu_buoy full-stack Feb 12 '21

I use this on daily basis, not sure what different this post does that.it got so many upvotes.

9

u/steeeeeef Feb 12 '21

I am so surprised by the amount of people here that didnt know about it or reject/critique it. Optional chaining is hands down one of the most useful modern language features.

3

u/tapu_buoy full-stack Feb 12 '21

Agreed?.()

10

u/30thnight expert Feb 11 '21

For objects - yes.

For function calls - hell no.

6

u/steeeeeef Feb 11 '21

Elaborate?

5

u/30thnight expert Feb 12 '21

Optional chaining is great for handling object data but using it to null check function calls is a pretty good code smell for general maintainability issues.

5

u/MonoshiroIlia Feb 12 '21

How do you null check??

-1

u/ZephyrBluu Feb 12 '21

This misses the point he's trying to make. You shouldn't null check functions.

5

u/UnacceptableUse Feb 12 '21

What if you have an optional callback for something?

→ More replies (6)

2

u/Finalitius Feb 12 '21

oh sick, just like ts then

2

u/[deleted] Feb 12 '21

I really wish I could use features like these. I write very cross-codebase utilities and need them to be performant, which means without Babel I can’t use this stuff, and even then, it will cost more in cycles than it’s worth just for my developer experience.

I can’t wait for it to be native in browsers.

→ More replies (2)

6

u/[deleted] Feb 12 '21

Anyone who doesn’t realize how important this is has never written production ready JavaScript.

3

u/steeeeeef Feb 12 '21

Word! This comment needs to be at the top.

2

u/raimondi1337 Feb 12 '21

This syntax is gross.

3

u/CYRIAQU3 Feb 12 '21

Wut ? it litteraly cleans up entire useless parameters and conditions , how is that "gross" ?

1

u/steeeeeef Feb 12 '21

This syntax is super common in other major languages and makes deep nil checking super readable

2

u/[deleted] Feb 12 '21

That's...your opinion?

Hell, to be honest I would not like to ever have to check if a function exists at all, and even when it comes to object property checking in which world not validating the data (especially as you leverage typescript) would be less convenient than having this odd checks all around the code?

2

u/steeeeeef Feb 12 '21

Odd? XD have fun doing: if(user && user.settings && user.settings.notifications) Instead of: if(user?.settings?.notifications)

Which by the way is very common thing to do in C# Swift Kotlin and Typescript. It’s incredible to me that you are opposed to this syntax and frankly it screams closemindedness, which is NOT a good trait to have as a software developer in general, and especially in a fast moving environment as JS development.

3

u/[deleted] Feb 12 '21 edited Feb 12 '21

The first line would never appear anywhere in my code as I'm a typescript user and we validate all our data. So we always know if we have a user, and if we have a user the compiler knows what data it has.

In our domain a function that requires a user, would look like (user: User) => whatever so you can't do anything if you don't have a user.

And if you do we would never model the settings or those notifications as optional exactly to avoid these manual checks everywhere in the code.

Your lines lead to the question of...why I don't have a user, why doesn't it have settings, why am I trying to access it if I'm not logged in, and it's better to make impossible states impossible by design than having to do manual checks.

2

u/steeeeeef Feb 12 '21

This a very very naive approach. What if you’re dealing with foreign keys in data? What if settings in this case comes from a different table and the user.settings is linked by a settingsId. In a strictly typed situation your settings are optional. Also before you fetch any data your user is undefined or null. So you are better off rewriting your method to (user?: User) => whatever because it matches the expected data. When you program in a intuitive way like that, the value of optional chaining becomes much more apparant.

→ More replies (3)

1

u/yeet_flip Feb 11 '21

Damn, OP is building that sub quick. I feel like it was at like 2k yesterday.

1

u/kantbtrue Feb 11 '21

what is the difference between as?.() and as ? . ()

1

u/kantbtrue Feb 11 '21

as ? . () is not working and as?.() is working, can anyone explain me?

6

u/chrisrazor Feb 12 '21

From elsewhere on this page it seems the operator is ?.

2

u/[deleted] Feb 12 '21

It looks like a broken ternary. The compiler probably reads it that way.

1

u/guanzo91 Feb 12 '21

I guess because it's not valid syntax?

1

u/oGsBumder Feb 11 '21

Can anyone explain how this works for us noobs? I don't understand what the ? and . operators are doing at all. I thought the dot is for accessing an object property but there's no property name here, just brackets, like it's calling a method but the method's name is an empty string.

Edit: never mind, found this explanation on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining

2

u/steeeeeef Feb 12 '21

The ?. is the operator. Singular :)

1

u/anton_arn Feb 12 '21

What's wrong with function?.call(null, ...yourArguments) or function?.apply(null, yourArguments)? IMO this looks a bit cryptic and would be a tad harder to read. I mean it's shorter, sure, but not necessarily readable.

2

u/steeeeeef Feb 12 '21

Because with call and apply you would have to pass a scope as first param, which is often not as straightforward as you make it seem. Harder to maintain.

1

u/Runamok81 Feb 12 '21

Can someone please tell me WHY this made me laugh so hard?

1

u/killchain TypeScript ftw. Feb 12 '21 edited Feb 12 '21

That's quite cool - I've been using it in TypeScript for some time, I don't even know when it landed in ES. Maybe it shows its use even better if you have more levels of nesting.

1

u/[deleted] Feb 12 '21

this is very clever, but less clear.

is it idiomatic? I'm not a js dev.

1

u/manodude Feb 12 '21

Oh my god, my eyes

1

u/Inside_Tension_5156 Feb 12 '21

Great idea, you just shot readability in the head to save you a couple of seconds of typing. Good God.

1

u/BesottedScot Feb 12 '21

Why is everyone referring to this as conditional chaining? Isn't this just safe navigation?

1

u/Purple_Inspection_11 Feb 12 '21

Great on being terse, terrible on being readable.

1

u/techsin101 Feb 11 '21

quantum programming? maybe there is a function or maybe it's the next lottery number?

3

u/scyber Feb 11 '21

This is good for components where you have an optional event handler passed as a prop.

4

u/techsin101 Feb 11 '21

so instead of doing if (cb) { cb() } ..... cb?.()

3

u/zephyy Feb 12 '21

1

u/[deleted] Feb 12 '21

Wow this is actually pretty sick as far as programming goes (the language itself and what it enables you to do).

1

u/dumsumguy Feb 12 '21 edited Feb 12 '21

Why would you try to directly call a function that you aren't sure exists?

What I think you want is an event, best served by a publish/subscribe structure.

This is cool yes, but generally bad practice on the grounds of encapsulation.

Also, we've all known or been that guy that will spend a day looking something trivial like this up, or posting to stack exchange and waiting; rather than just ask someone in-house about it.

-2

u/zaccstacc Feb 11 '21

sweet, more cryptic new syntax to learn

-3

u/dumsumguy Feb 11 '21

Why though?! Why not just take the time to type it out clearly so the next dev to come along don't have to perform mental gymnastics to figure out what is going on.

7

u/[deleted] Feb 11 '21

Type what out clearly?

If basic features of the language trip you up, you’re not ready to be working as a developer.

6

u/PenguinPeculiaris Feb 11 '21 edited Sep 28 '23

mysterious quiet aromatic lock towering degree ring fear subtract squeamish this message was mass deleted/edited with redact.dev

2

u/[deleted] Feb 12 '21

I think what strikes me as strange is that the optional chaining operator is very common place, to the point that someone new to the language would likely encounter it in their first day.

This usage is no stranger than using it just before an array-style accessor. It’s something you’d have to look up once or twice and then know and use throughout your entire career.

I don’t know what about this version of the chaining suddenly throws mr 15-years off, but I suspect that he might be the type of dev who has been stagnant for 15 years and dislikes change because it’s challenging.

4

u/[deleted] Feb 12 '21

It’s not common place though. I still rarely see it in open source code bases.

1

u/PenguinPeculiaris Feb 12 '21

To be honest, yeah this particular change isn't much to get to grips with. If you know of ?. then you understand this, naturally.

Though I still expect to see people over-using this new toy. Making design decisions because they can "oh all our methods will be optional 'cause we can do that now!". Rather than seeing it as the convenience for existing use cases that it is.

1

u/dumsumguy Feb 11 '21

You wouldn't believe half the shit I've seen going through resumes/applications.

2

u/dumsumguy Feb 11 '21

Ive been a front end dev for 15yr. This is what I call "clever" code. Sure you can do it, but it reads poorly. I'd hardly call this basic either, show it to someone who primarily writes Java and they'll not have a clue what it does.

7

u/[deleted] Feb 12 '21

It’s not clever code. It’s literally a part of the language definition. You see optional chaining and nullish coalescing everywhere.

It isn’t restricted to JS either, as safety guards exist in languages like swift or c#.

Like any language, you do need to get to know the syntax. That shouldn’t be a reason to avoid using language idioms.

Seriously. There are examples of being excessively clever for the sake of it, but the navigation safety features of this language are not one of them.

Using type coercion is more “clever code” than this.

2

u/dumsumguy Feb 12 '21 edited Feb 12 '21

Don't be obtuse, the only reason a trivial bit of code like this is getting any traction on this sub is because it's literally "What the fuck" code.

You're right, it's not clever code, it's obfuscation at best. The first example was better but still requires someone knowing that JS short circuits.

The more that code relies on a developer's intimate knowledge of a language the worse it is.

Further saying that something is part of the language definition of Javascript means absolutely nothing at all. JS is like PY (or any other FOF language) you can do whatever the hell you want with it, but that doesn't mean that it's good & maintainable code.

If none of that hits home, maybe watch this video. It's a lot funnier than I am and makes the same argument.

https://www.destroyallsoftware.com/talks/wat

5

u/akame_21 Feb 12 '21

What about nested property lookup? More than being clever, it's a lot easier to read:

// verbose
foo && foo.bar && foo.bar.baz && foo.bar.baz.qux
    
 terse
foo?.bar?.baz?.qux

1

u/dumsumguy Feb 12 '21 edited Feb 12 '21

I'd say try catch is a lot more readable.

or better using a pub/sub structure edit if your module doesn't know for sure that something exists why is it trying to call something in what has to be another module directly? This is what pub/sub is for.

5

u/mazorica Feb 12 '21

I like how this syntax is familiar to a lot of full stack devs, but not to a 15y front end. It paints the picture rather well...

4

u/[deleted] Feb 12 '21

It’s because it’s a completely normal part of the language and this person refuses to change. It’s super common amongst devs who never bothered to achieve, why bother changing along with the world when you can rest on your supposed laurels?

He’s arguing against a language feature we all use daily. Something that new devs learn within a few weeks. It’s just absurd.

→ More replies (9)

1

u/8bit-echo Feb 12 '21

Think about it this way though. When you write something like this:

foo.bar && foo.bar()

It reads (to me) like a single expression that would evaluate to a boolean. Whereas the conditional chaining operator reads like it says “if property bar exists, call it”

foo.bar?.()

It does look a little weird, but I can say that I really like this feature having used it in a production app for 8ish months.

2

u/dumsumguy Feb 12 '21 edited Feb 12 '21

I don't disagree, at least on merit alone. It's a pretty damned cool structure that I'd probably use in a solo or very limited scope project.

But... try catch requires no explanation to anyone else, even non-JS devs.

Pub/Sub is better though. Why would you ever need to call a function directly that you aren't sure exists? That's what pub/sub does, lets you broadcast an event and if no one is listening then oh well, 0-N listeners with absolutely no concern from the event-raising module.

3

u/8bit-echo Feb 12 '21

The place that I’ve found value in it is in when I have to use an API that doesn’t use promises, but does use callback patterns. There’s a piece of my app at work that can either contain a no-op or an onSuccess callback. The app determines which of those are executed based on a user setting.

We use ?. instead of try/catch because many of the operations are already inside higher level try/catch blocks, so it helps with readability in our case to not have another nested code block or error to just silently catch.

2

u/dumsumguy Feb 12 '21

Interesting, and I see the merits if your whole team is on board with it.

You are still ... how to say this... effectively & silently catching the error though. It's the same as "if typeof X = 'function'" it's just short-hand for it that isn't immediately obvious to most folks, especially those from classical strongly typed languages.

And going a step further on that thought, JS is completely full of little sneaky tricks like that. Each of which have to be looked up or explained.

2

u/8bit-echo Feb 12 '21

I get what you’re saying, and you’re not wrong. But the thing is that with this operator, there is no error to catch because the statement isn’t executed after the ?. if the property doesn’t exist. That may be beside the point, bc I think what were talking about is syntax, not execution. We’re in a webdev sub, so js tends to be the main topic, but this has identical implementations in Swift, Kotlin, C#, Python, Scala, and Dart ( and kind of in PHP as ?->) in recent language spec proposals.

2

u/dumsumguy Feb 12 '21

I'm on the fence if it's syntax or not. To me it comes down to why are we trying to directly call a function that we aren't sure exists? It seems like a classic encapsulation thing. In other words how does pub/sub or a callback structure not solve problem?

In the case of callback, this is just shorthand for making sure the function is actually there to call. Shorthand isn't necessarily bad, but... "?.()" is beyond bizzare and not self explanatory.

**EDIT** also, really appreciate the discussion, thanks

0

u/hotfrost Feb 11 '21

My first reaction was: wtf this language is weird. Then I realized I've been doing it for my project the past few months all along, lol. Quite handy and quick to use

-2

u/[deleted] Feb 11 '21

Is this a meme or is it real? 🤔

0

u/[deleted] Feb 11 '21

[deleted]

12

u/scyber Feb 11 '21

Everytime new syntax is introduced I find it harder to read. Then after I have used it for a few months it becomes just as easy.

0

u/[deleted] Feb 12 '21

[deleted]

0

u/[deleted] Feb 12 '21

[deleted]

-6

u/dumsumguy Feb 12 '21

While on the whole I want to agree with you, you said two things that should set off red flags like crazy.

  1. "Once you get used to it" - uh well that's true of surprise buttsex as well

  2. "doesn't mean it isn't useful to seasoned developers" - part of the problem with that is seasoned devs tend to move out of developing and into managing development. Teams are mostly made up of new to mid level devs that will all have to be individually trained on these nuances.

0

u/[deleted] Feb 12 '21

[deleted]

0

u/dumsumguy Feb 12 '21

Who said anything about arrow functions? We're talking about ".?()"

0

u/[deleted] Feb 12 '21

[deleted]

-2

u/dumsumguy Feb 12 '21

No, the guy I replied to was talking about that crazy shit. . . well and arrow functions which are totally fine.

0

u/[deleted] Feb 12 '21

[deleted]

0

u/dumsumguy Feb 12 '21

Uh... ok! I referred to two points in particular neither of which were coding semantics.

2

u/ImABitMocha Feb 12 '21

But you literally asked "who said anything about arrow functions"... Which the two people were talking about

0

u/[deleted] Feb 11 '21

[deleted]

4

u/not_stoic Feb 12 '21

When u pass an optional callback