#Proposal - revert PR 7584

184 messages · Page 1 of 1 (latest)

forest jacinth

So PR 7584 has caused a lot of issues for me personally and I'm sure I'm not alone since I've seen some reactions on some discussions about this same topic. Basically that PR made it impossible to find a builder and modify it from an array of builder classes for example, or any place where you're not aware of what data you have and where. I, for example, have a system where an indefinite amount of buttons is pushed to an array and then action rows are made out of them, and later, once each button is clicked, I have to disable them and update them in the message on Discord. This has been made impossible since you can't use the built structures to find a property with a certain name, nor can you modify the received structures after finding the one you want.
I initially proposed to add back getters in a PR that I later closed for reasons I now regret but I believe it is better to revert the PR entirely, as it, in my opinion, simply adds clutter and complicates a lot of simple code bases and makes situations where we are agnostic of the data we are building (when it comes from external resources) and want to modify it. I would like to hear from the maintainers on this to know if this is the desired approach or not, so that we can discuss a solution that fits everyone.
PR link for reference: https://github.com/discordjs/discord.js/pull/7584

ancient plank

yes please

I don't really care about the reasons for needing it reverted, but the PR made everything massively annoying to use

forest jacinth

yep that was the reaction I was talking about

ancient ruin
forest jacinth So PR 7584 has caused a lot of issues for me personally and I'm sure I'm not alo...

I've provided solutions to all the problems that you've faced that are less lines of code and more efficient but you've failed to accept them for some reason. And would prefer to repurpose custom ID's as a references and action rows as maps. All of which are wrong use cases. Furthermore the old behaviors allows users to modify the cache directly whereas it's not possible now. In addition, some builder structures aren't symmetrical when sent back in forth such as TextInputComponent, so representing them as a single structure makes no sense anyways. I want to reiterate that a bunch of other discord libraries don't have getters on their builders, so you'll also need to explain why discord.js is an exception here.

I was blatantly told that this solution was stupid? Because I had to use a map instead of iterating through an entire action row everytime I needed to access an element

ancient plank

so you'll also need to explain why discord.js is an exception here.
cuz its js and not java or php or rust or whatever

ancient ruin

but the design pattern is the same

you don't have to use builders we have json

forest jacinth

The issue with discord.js is that these classes have always worked both ways and were never explicitly and exclusively builders. You’re always bringing up other libs from other languages when in reality that shouldn’t matter at all. This is JS and this is discord.js. The users are used to a specific behavior and will not like this transition as it makes stuff unnecessarily complicated and the average user will not be able to upgrade seamlessly.
That solution you gave me might work and might even look better, but this isn’t and cannot be about me. If I had these issues in 3 different places in my relatively small bot who knows what other people with bigger bots on more servers will face. In my case I can stick to customIds just fine, but what if someone else needs that AND a label? They just can’t do that now with this split

ancient ruin
forest jacinth

And you might argue that you’d be able to find solutions for the other users but would you be able to do that for 100.000 people when v14 launches publicly? You really cannot stick to one case only because we’re working on a dev version used by very few and on which even fewer give feedback

ancient ruin

Yuudatchi our moderation bot has no issues despite it heavily using componentns

forest jacinth

Literally anything is possible

ancient ruin

yes and my answer can be generalized

The answer is to not use custom_id's as a replacement for references and to not use action rows as replacement for maps. In essence use the data structures appropriate for the task

forest jacinth

now go tell 100k people that

ancient ruin
ancient ruin

it's just a breaking change

like every other rename or removal

in fact I might add a section in the upgrade guide

in similiar fashion to how the removal of .deleted was presented

forest jacinth
ancient ruin
forest jacinth

you got an answer from 1 person that is disregarding agnostic functions, they always assume you instantly know everything you put into a builder, which may not always be true, although it will be 90% of the time

ancient ruin
tardy bison

Could someone show a earlier - now code?
want to judge it neutrally

ancient ruin

sure

I can give two examples actually

forest jacinth
forest jacinth

I don't think those are the examples he was looking for, they're different ways to do the same thing but they don't really touch the core issue with the props

ancient plank
ancient ruin

sure

ancient ruin

Yes

tardy bison

Btw the .get option seems to be more suitable, better for typescript and less code

ancient ruin

Wdym

tardy bison
ancient ruin

Oh for the map yeah

tardy bison
ancient ruin

yes

shell lantern

Tiny bit off topic but still on the topic of the PR, but I don't see why this couldn't be supported with generics or a different type altogether?

Is it seriously impossible to represent a value as non null there?

I feel like a lot of decisions the lib has been making are making developers have to work harder not smarter, by writing more code for little to no gain in devex.

ancient ruin

yes it is impossible because if it was non-null, the types would be inaccurate

it's holds partial API data

it's even worse with text input components that returns data in a different shape than it's builder

shell lantern
ancient ruin
ancient plank

it is/was nullable in the builder but not the discord api data

shell lantern

Could you not support a generic or use a different altogether to represent embeds specifically in message.embeds?

ancient ruin

the core issue is that the received components would mark types as optional when in reality they could never be

tardy bison
ancient ruin
shell lantern

so it'd fix the original issue though

ancient ruin

what?

ancient plank

and you could just add a clone method

ancient ruin

that was actually brought up internally, clone method still doesn't address mismatched received types and shapes

ancient plank

generic & clone

ancient ruin

yeah but generics still don't address shape changes. They can only address types

and you can make data from the API mutable anyways via Builder.from(receivedComponent)

also massive amounts of js users can ignore those types without even noticing or incurring an error of any kind

shell lantern
ancient plank

I never had issues with custom_id being nullable in ts before the change

a non-null assertion takes care of it for the few times I need the id

ancient ruin

point is you shouldn't need a non null assertion to begin with bc it's already well-defined that it won't be null

ancient plank

is a single operator in ts only land really worth it

ancient ruin

and again what about structures like TextInputs that have different structures

shell lantern

What about interaction.client.user being nullable, yet it cannot be null?

ancient ruin

it can be?

if you're not a bot user it can be null

shell lantern

its impossible to use djs without a token

and to get a token you need a bot application

ancient ruin

you know you don't need a bot user for slash commands right?

shell lantern

You do if you want to use discord.js, the library we're using

ancient ruin

nope

that's just incorrect

shell lantern

Really? Spin up a working djs bot that doesn't use a bot application and send me a link to the repo

ancient ruin

I mean I can, but like I'm not going to do that right this minute

shell lantern

Do it when you can and ping me, i'll bet $5 you can't lol

ancient ruin

sweet sounds good

ancient ruin
shell lantern
ancient ruin

that has nothing to do with client.interaction.user being null or not.

shell lantern

djs communicates only over ws

to communicate over ws you need a token, and then you'll have a client instance. its not pulling the client from each interaction, the client is constantly passed around to every part of the app.

ancient ruin

alright this is going wildly off-topic

forest jacinth

you can even cast the types

have a type generic boolean called Received

stuck hornet

some of the typeguards in the interaction class could narrow the type of the client prop

forest jacinth

if true, some props will be of type never

ancient ruin

furthermore as I stated earlier and in my PR it's not the responsibility of a builder to represent data, why? bc it's a shitty container for representation as it's mutable. It also would have two responsibilities of partial construction and representation. They're being stretched too thin. In general classes should be good at a single set of related responsibilities

forest jacinth

the ! operator in TS exists for a reason. You simply have to know when a property can be null and when it can't, and add the appropriate checks to your code if needed

just because a prop can be null it doesn't mean it will always be null in every code sample

ancient plank

to me it seems like the solution was way over engineered for a problem that no one really had

ancient ruin
ancient ruin

In fact the recommended typescript/eslint rules will default to warning whenever it's used

limber lark

I'm just going to dump my thoughts

  • no I don't think it should be reverted, discord.js should not be using builders to represent received components
  • the received components should be immutable
  • maybe a .toBuilder() method could exist like a clone, idk. This would give you a mutable version without comprising cache, or types for nullable props, or difference in structure
  • stop complaining about TS actually imposing strict types. If you don't want proper strict types, go back to JavaScript
  • builders suck anyway
hollow flume

I for one don't see why we should revert the PR you linked. It finally shows the clear separation between data received from the api and a builder you may use to build raw data, including perks like validation and cleaner code, and theres literally a method to convert from data to builder

limber lark

Oh that method already exists, perfect. My third point stands

forest jacinth
forest jacinth
ancient ruin
hollow flume

what is the end goal here

limber lark

The not-null assertion is for situations where the typing system cannot strictly type it as being not null even though youre sure it will never be. This is not that situation because we literally don't have that issue in the current split.

Planning to intentionally use not-null simply to make code easier or cleaner is an improper use of TS

forest jacinth
hollow flume I for one don't see why we should revert the PR you linked. It *finally* shows t...

if you have an array of received buttons you can't modify them all, even with that method. You either access their properties or modify them, you can't have both and that's the issue I'm trying to get at here. All that PR did was separate something we had in 1 class into two, generating more confusion among end-users who will be confused as to why they can't construct the new classes and when they figure out they need to use the builders they will be confused why they can't access their properties. Again I mention: if I, with a small bot, faced 3 different situations where I couldn't convert my code how many more will thousands of others face?

forest jacinth
hollow flume

i'm sorry to say it bluntly, but you're literally the only one with that issue...

forest jacinth
limber lark
hollow flume

even with that method wrong? Once you build a ButtonBuilder from the data, call .setWhtever

forest jacinth
ancient ruin
forest jacinth
limber lark

Well that I completely disagree with, I'd lean heavily to the getters

forest jacinth
hollow flume

The getters are just a lazy shortcut to builder.data

forest jacinth
limber lark

Yeah but camelCase is very important supposedly, that's why the getters existed

forest jacinth
hollow flume

Builders always have and should always be JUST taking in chained methods and returning api data

limber lark

I mean it's not wrong, there's just an additional factor to consider

It's a lazy camelCase shortcut

forest jacinth
limber lark

Make one data getter that returns the object in camelCase

Change the other to _data

hollow flume
forest jacinth
limber lark

I know lol

hollow flume

look at slash commands

all fields are exposed in snake case

as they should be

limber lark
forest jacinth
hollow flume

oh boo hoo

they don't even stay in ram for long

come on

thats like crying that validation slows down creation by a few nanoseconds

actually technically

it'd be more like

const actionRow = ActionRowBuilder.from(message.components[0]);

actionRow.components.find(item => item.data.custom_id === '123 bite me please')?.setDisabled(true);

await interaction.editReply({ components: [actionRow] })

or it should be

forest jacinth

because the buttons inside the action row are immutable

hollow flume

read again rodry

read again

const actionRow = ActionRowBuilder

forest jacinth

yeah the row is a builder, the components inside of it aren't

right?

hollow flume

well for one that method doesn't exist yet because Thonk

but if it did exist it'd convert data to builders

hollow flume

its not

Sadge

limber lark

But if it was your whole example doesn't work?

Wait, read-only on that prop but not the nested components?

hollow flume

yes

limber lark

Gotcha

hollow flume

if the .from method existed and components was declared as a public readonly field (so you can't do row.components = []) it would work

limber lark

And the things in the components array were also builders

hollow flume

hmm

sec

forest jacinth
forest jacinth
ancient ruin

Yes bc I coded it to be that way