#[MEGA THREAD] Get Your Code Reviewed or Review Others

1 messages · Page 8 of 1

round fossil
#

which is like, if u have a std java immutable map, so w guava it wouldnt work

pine grail
#

yeah

#

how do you expect them to check that

jagged rock
#

I like the kotlin approach of Maps and MutableMaps being separate

#

:)

pine grail
#

that is definitely one of the solutions of all time

dense leaf
round fossil
opaque plover
dense leaf
#

i know

#

i just

#

love it

opaque plover
#

righttt

#

you're obsessed with it

#

you're all over it

#

😉

dense leaf
#

potentially

opaque plover
#

js like me and raydan

#

ngl

round fossil
#

when we don't have mapOf(k to v, k1 to v1,...) so we need ImmutableMap.Builder copege

#

yeah but its much more verbose (ofEntries() )

#

well not that the builder isn't but mye

sly jackal
#

is there no map.of(k1, v1, k2, v2)?

#

or was I dreaming

round fossil
#

yes but it only goes up to like 9 entries KEK

sly jackal
#

oh

#

yikes

round fossil
#

fr

sly jackal
#

I mean you have to be a little crazy to hardcode more than 13 entries by hand

dense leaf
#

yeah

sly jackal
#

unless its like a lookup table or something

round fossil
#

yup

dense leaf
#

this is why there should be syntax sugar for pairs

#

and just have it be a vararg of pairs

round fossil
#

well kotlin has the first class higher order infix (maybe inline) to function

dense leaf
#

yeah

#

infix my beloved ❤️

round fossil
#

tbh im lil jealous

opaque plover
#

infix is super cool

round fossil
#

yea I mean I get it can be a bit confusing also, but it has its place

opaque plover
#

perchance

dense leaf
#

haven't found a good usecase for custom infix yet

round fossil
#

I mean the way its used in the gradle api is nice

opaque plover
#

i so badly want to find a usecase for abstract extension functions

#

that would be really cool probably

dense leaf
#

lmao

#

idek how that would work

opaque plover
#

same

#

it probably doesn't work

#

but you showed it to me

#

so now i am in two minds

late smelt
#

There’s Map.ofEntries

round fossil
#

yes but its so verbose

dense leaf
#

kotlin stdlib ❤️

late smelt
#

Just make your own compiler hack

#

Kek

round fossil
#

Map.ofEntries(Map.entry(k1,v1),...) KEK

round fossil
#

lombokotlin

dense leaf
#

lombokt

opaque plover
#

lombo.kt

#

why is there no kt tld

#

ffs

dense leaf
#

smh

opaque plover
#

but there is a java tld apparently

#

wtf

dense leaf
opaque plover
#

warm take: every two letter combination should be a tld

#

maybe even three letter but that's a stretch

dense leaf
#

.rad

opaque plover
#

based

dense leaf
#

fonts.rad

#

crazy domain

junior holly
surreal peak
#

i would specify what semantics RegistryInterface::getRegistry() has in that class

#

immutable, unmodifiable view etc

alpine anvil
dense leaf
#

damn

surreal peak
#

also whats te point of that logging

round fossil
# junior holly https://paste.md-5.net/dapiyupibu.java Could I get some feedback on this? Pract...

you're using the abstract/base design pattern slightly wrong

usually u'll see sth like this:

public abstract class AbstractRegistry<T> implements RegistryInterface<T> {

    protected abstract Map<String,T> getBackingMap();

    @Override
    public Map<String, T> getRegistry(){
        return Collections.unmodifiableMap(this.getBackingMap());
    }

    /**
     * Registers an object with an associated key.
     *
     * @param key The key to assign to the value.
     * @param object The object to register.
     */
    @Override
    public void register(String key, T object){
        if (key == null || object == null) {
            throw new IllegalArgumentException("Key or Object cannot be null");
        }
        this.getBackingMap().put(key, object);
    }

    /**
     * Unregisters an object with associated key.
     *
     * @param key The key to unregister.
     */
    @Override
    public void unregister(String key){
        if (key == null) {
            throw new IllegalArgumentException("Key cannot be null");
        }
        this.getBackingMap().registry.remove(key);
    }

    /**
     * Get an object from the registry.
     *
     * @param key The key used to get the object.
     * @return Returns the object found with associated key.
     */
    @Override
    public T get(String key){
        T object = this.getBackingMap().registry.get(key);
        if (object == null) {
            Bukkit.getLogger().severe("Object with key " + key + " not found in " + this.getClass().getSimpleName());
        }
        return object;
    }
}
#

also ur singletons are not thread safe in case u're gonna access it across multiple threads

surreal peak
#

smth like this:

one minute later, still waiting on what comes after the this

round fossil
#

haha yea idk discord editing mode is so goofy

#

also you may wanna life cycle a root registry that holds all the other registries, that way u don't need to have the arbitrary lazy initialization but use a more defined initialization stage

surreal peak
#

RegistryRegistry :}

dense leaf
#

just use nms registries bro

round fossil
#

they're nice but they're a bit too tied to minecrafts need

dense leaf
#

i love em

round fossil
#

I mean obv u can just grab ur own mapped registrty instance, but like u'll need to define lifecycles, intrusive holder possibilities etc

dense leaf
#

i copied some of yarn's mapped registry code and improved it for bukki

#

t

#

like changing Identifier/ResourceLocations to NamespacedKeys

round fossil
#

yea

dense leaf
round fossil
#

myea looks fine but u did that in java

#

thats surprising

dense leaf
#

yeah i could NOT be bothered to rewrite them in kotlin

#

too many lambda and nullability errors

#
  • generic errors concern
#

and then i just

round fossil
#

ah java code is just that bad u say?

dense leaf
#

yup

#

especially from mojank

alpine anvil
#

java and kotlin in the same module !?!!

dense leaf
#

hehehe

surreal peak
#

i do that too 👉👈

round fossil
#

i feel like thats way nicer if u write it with interoperability in mind

dense leaf
#

this is why i write all my libs in kotlin

#

so java users feel left out

#

like they should /j

round fossil
#

banned*

surreal peak
dense leaf
#

:(

#

well

#

initialisation loops

surreal peak
#

💀

dense leaf
#

idk man

#

it works

surreal peak
#

if only we ahd unsafe::ensureLoaded

dense leaf
#

unsafe concern

#

i mean uhh

surreal peak
#

class.forName(AceRaceGameData.Companion::class.java) then

dense leaf
#

it's currently still json, but will be nbt soon™

#

i could probably improve a lot there

surreal peak
#

now i see why people hate on kotlin

dense leaf
#

but that was when i was new to dfu

#

so it's automatically legacy code

round fossil
# dense leaf i mean uhh

i mean this looks so nested, but yea I suppose some nicer formatting would make it looks more beautiful than java (ever would)

surreal peak
#

doubt

round fossil
#

🤨

dense leaf
#

this better

surreal peak
#

no

dense leaf
#

the codecs are kinda just

#

yeah

dense leaf
surreal peak
#

💅

dense leaf
surreal peak
#

maybe remove explicit type

dense leaf
#

won't work

#

i think

#

idw open ij rn

surreal peak
#

why open ij when you have nvim

dense leaf
#

because kotlin lsp is so fucking shit

surreal peak
#

hehehe 🤡 🤡

gilded gate
#

I want to add a new entity that works like any other entity

#

will that requires NMS?

dense leaf
#

fabric

surreal peak
#

ig

gilded gate
#

no plugin

dense leaf
#

not possible

#

also wrong channel

gilded gate
#

oh yh sry

junior holly
#

Really gotta get this netty lesson from trooper lol

round fossil
#

ur singletons are not atomic

#

Like if two threads access the singletons concurrently there’s a chance u get two instances instantiated or even more

junior holly
#

OOP wise I mean, I think it’s pretty good, reusable, expandable, and when I fix a couple things thread safe.

round fossil
#

well

#

Its not bad, but as I mentioned above

dense leaf
round fossil
#

And also you may wanna explicitly rely on CononutMap blah = new ConcurrentHashMap

dense leaf
#

CononutMap

round fossil
#

Yes thats true

#

I mean I think just naming it Registry would be fine

rancid fern
#

^

junior holly
#

Noted, I will fix those things. Whatcha think of the idea?

dense leaf
#

the idea

#

brilliant

late smelt
#

Everyone loves a good registry

dense leaf
#

net.minecraft.registry on top

alpine anvil
#

sh.miles.pineapple.collection.registry on top

late smelt
#

Is that like coconut mall

alpine anvil
#

no its like the coconut nut is a giant nut

late smelt
#

What

junior holly
glacial stream
#

I made my own event that fires every time a player's equipment changes which I'm using for an NPC that copies a players actions. I appreciate any feedback especially if I made mistakes that ruin performance.

Event: https://pastes.dev/Jhr9RUkqts
Listeners: https://pastes.dev/dThl1udkoJ

It's pretty long so thanks in advance for anyone trying to read it

rancid fern
glacial stream
rancid fern
#

They might be too new for the version you're using

gilded gate
dense leaf
#

are you really extending craft bukkit classes

#

// Adjust this value to control the shake intensity
chatgpt intensifies

gilded gate
#

em no

#

a friend helped

dense leaf
#

also don't hardcode skin textures

late smelt
#

EntityPig isn’t a craftbukkit class

dense leaf
#

is it not?

gilded gate
#

yes

dense leaf
#

i just saw a import net.minecraft.server.v1_16_R3.*; and thought it was

gilded gate
#

craftbukkit is CraftEntityPig

late smelt
#

EntityPig is an NMS class

dense leaf
#

even worse

#

o yeah mixed them up

dense leaf
dense leaf
gilded gate
#

well chatgpt is bad when using NMS

gilded gate
#

the IDE did

dense leaf
#

yeah then disable that

gilded gate
#

and it wont let me

#

idk why

dense leaf
#

literally just google it lmfao

opaque plover
dense leaf
#

yea

sly jackal
#

why google when you can ask chad gpt?

surreal peak
#

you forgot chatgpt

cobalt trellis
#

I haven't used YT for dev stuff that often really. But ChatGPT is completely absent in my dev workflow

surreal peak
#

same, there are better models

#

or just not using ai at all

dense leaf
surreal peak
#

im not gonna write things 255 times over using ai to generate it

glacial stream
#

I use AI to make my code more efficient, after it's already working

#

or for math

late smelt
#

Probably ends up making it less efficient

dense leaf
#

yeah

glacial stream
#

shit

cobalt trellis
surreal peak
#

opcodes

glacial stream
# late smelt ~~Probably ends up making it less efficient~~

This is my last time using chatgpt, which one is better?

public void before(List<EntityData> list){
        List<EntityData> clone = new ArrayList<>(this.list);
        List<EntityData> result = new ArrayList<>(list);

        Set<EntityData> removal = new HashSet<>();
        for (EntityData data : list) {
            for (EntityData d : clone) {
                if (d.getIndex() == data.getIndex() && d.getType() == data.getType()) removal.add(d);
            }
        }
        clone.removeAll(removal);
        result.addAll(clone);
        this.list = result;
    }```
   ```java
public void after(List<EntityData> list){
        List<EntityData> result = new ArrayList<>(list);

        for (EntityData data : this.list) {
            if (result.stream().anyMatch(d -> d.getIndex() == data.getIndex() && d.getType() == data.getType())) continue;
            result.add(data);
        }
        entityMetaData = result;
    }```
#

the goal is to add this.list to list, without duplicates because I'm using metadata packets so I have to open up the EntityData and compare the index and dataType

eager wasp
#

You could just put it in a Set if you want to not have duplicates.

late smelt
#

Depends if the values properly implement equals and hashcode

glacial stream
late smelt
#

That’s what equals and hashcode are for :p

glacial stream
#

ah, probably not because entityData contains an index, dataType and value. And I only need to compare the index and datatype and the value can be unique

sly jackal
#

I mean maybe ai can optimize certain functions, but the reasons for why you made those functions in the first place may be wrong, so all AI is gonna do is polish a turd

#

im not saying thats what happened it this case cus I havent read it

#

its just from what I know tends to happen

glacial stream
#

Yeah the only reason it works for me is because I'm intermediate, if you've been programming for years you are probably better than the currently available AI chatbots

#

and obviously I don't just copy paste AI's code, I read it, compare it and logically conclude which is better for what I want

surreal peak
#

not too difficult to be better

glacial stream
#

rn it's pretty mediocre, but eventually it will be better than everyone

sly jackal
#

doubtful

#

it has nothing more to learn

#

it can only be as good as the combination of everyone humans have already done

glacial stream
#

lets agree to disagree lmao

sly jackal
#

sure

cobalt trellis
# surreal peak opcodes

even for that you generally do not need to do so - unless you are reinventing the wheel there

glacial stream
dense leaf
#

unreadable

#

java collection/stream operations look terrible and suck

#

kotlin.collections >>

glacial stream
#

thanks

dense leaf
glacial stream
# glacial stream thanks

I asked "why" for learning purposes and you answered in a respectable way. That's why I thanked you

tall trout
#
        cancelTaskForPlayer(player);
        Inventory inventory = player.getInventory();

        BukkitRunnable task = new BukkitRunnable() {
            @Override
            public void run() {
                for (int i = 0; i < inventory.getSize(); i++) {
                    ItemStack item = inventory.getItem(i);
                    if (item != null && item.getType() == Material.ECHO_SHARD && item.hasItemMeta()) {
                        if (item.getItemMeta().hasDisplayName() && item.getItemMeta().getDisplayName().contains("§aʀᴇʟɪᴄ ᴏꜰ §3§lᴛʀᴀᴠᴇʟ")) {
                            tickTravelTask(player, getRLevel(item));
                        }
                        if (item.getItemMeta().hasDisplayName() && item.getItemMeta().getDisplayName().contains("§aʀᴇʟɪᴄ ᴏꜰ §c§lᴇᴍʙᴇʀ")) {
                            tickEmberTask(player, getRLevel(item));
                        }
                        if (item.getItemMeta().hasDisplayName() && item.getItemMeta().getDisplayName().contains("§aʀᴇʟɪᴄ ᴏꜰ §6§lᴛʀᴇᴀsᴜʀᴇ")) {
                            tickTreasureTask(player, getRLevel(item));
                        }
                        if (item.getItemMeta().hasDisplayName() && item.getItemMeta().getDisplayName().contains("§aʀᴇʟɪᴄ ᴏꜰ §1§lᴍᴀss")) {
                            tickMassTask(player, getRLevel(item));
                        }
                        if (item.getItemMeta().hasDisplayName() && item.getItemMeta().getDisplayName().contains("§aʀᴇʟɪᴄ ᴏꜰ §4§lᴄᴏᴍʙᴀᴛ")) {
                            tickCombatTask(player, getRLevel(item));
                        }
                        if (item.getItemMeta().hasDisplayName() && item.getItemMeta().getDisplayName().contains("§aʀᴇʟɪᴄ ᴏꜰ §2§lᴛʀᴀᴅᴇ")) {
                            tickTradeTask(player, getRLevel(item));
                        }
                        if (item.getItemMeta().hasDisplayName() && item.getItemMeta().getCustomModelData() == 10) {
                            item.setAmount(0);
                        }
                    }
                }
            }
        };

        playerTasks.put(player, task);
        task.runTaskTimer(WardenRelics.getInstance(), 0L, 5L); // Repeat every second (20 ticks)
    }```
opaque plover
#

still comparing items with names

#

well

surreal peak
#

use the scheduler instead of summonining random bukkitrunnables

tall trout
surreal peak
#

?scheduler

tall trout
surreal peak
#

i mean just use the scheduler method (Bukkit.getScheduler().runTaskTimer()) instead of creating random bukkitrunnables for no reason

dense leaf
surreal peak
#

there are three ways to represent inheritance trees in sql databases:

  • a table for the whole tree (base + child classes)
  • table per child class
  • table for base, which stores the id of the child and a discriminator and the child data is stored in another table
oblique rover
#

Tell me if you find any possible optimizations

#

Or problems

#

src/shadow contains the actual optimizable code

surreal peak
#

remove .idea

clever crag
remote kiln
clever crag
tidal basin
alpine anvil
#

he has compact packages enabled

#

there classes along with those folders

remote kiln
tidal basin
#

That's even a bigger problem imo 💀

sleek shard
#

should have a seperate api package and a core package

#

would make the codebase so much cleaner :D

tidal basin
cobalt trellis
#

Such separation is usually overkill - instead try to treat everything that is public as public API

Or just use JPMS/jigsaw

#

Well ideally you do both

alpine anvil
surreal peak
#

make it AutoClosable if it really needs to be closed

#

actually makes more sense for "short" lived objects though

jagged rock
#

That Map<String, PunishmentData> part could be its own result class

woeful pasture
#

okay maybe its just me, but I've never understood @NotNull inside of Maps an arrays and such. Shouldn't it be implied, especially within a map that your key can't be null and neither can your value. In which case its just redundant to type

#

Nullability within array types seems excusable but outside of that it seems like it just clogs up unecessary space and makes things harder to read

#

riddle me this

#

if the key can be null

#

how do you identify the value of the null key

#

you should also not really ever have null values within the value of the hashmap

#

that's the wildest thing ever. Still such and edge case do you use it? If not its pretty much redundant

#

I don't think anyone expects such behavior

#

why

#

there can't actually be a good reason for such a key

#

I was just wondering why people did that

#

its always been the reason I use java5 annotations

#

because they can't go on those subtypes and IntelliJ doesn't try to coerce me to use them as such

#

no just at your entry in discor

#

nothing about your code seems wrong or seems like it needs to be tweaked though

#

ig my only question would be to the benefit of SavedPunishment itself

#

@night knoll ^

#

what is the ID related to?

#

player UUID or what

round fossil
#

Prefer Callable over Throwing.Supplier

#

u’re shutting down the executor improperly

round fossil
#

I mean you usually wanna shutdown, await termination (that is wait for any tasks that are still running to complete) and then in worst case scenario you can shutdownNow

#

now it highkey sucks because shutdownNow gives any tasks that weren’t finished, so u dont rly know how far they came before they were forcibly shutdown, i mean u could rerun eventual tasks given by shutdownNow, but eh, I mean I’d try to just have some sort of policy for the tasks I’m submitting to the ES in the first place

#

and yes this is what thread interruption lowkey “tried to address partially” but it’s cumbersome and often comes in the way so goofy java (ES being a prime example)

tall plover
#

Hey, could someone tell me if this code to add enchantments via PDC is great or not?

junior holly
sly jackal
#

does that even matter

#

p sure they already get cached

junior holly
#
public int getEnchantmentLevel(ItemStack item, String enchantName){
        if (item == null || item.getType() == Material.AIR) {
            return 0;
        }

        ItemMeta meta = item.getItemMeta();
        if (!item.hasItemMeta()) return 0;
        NamespacedKey key = new NamespacedKey(plugin, enchantName);
        return meta.getPersistentDataContainer().getOrDefault(key, PersistentDataType.INTEGER, 0);

    }

For example you create a new key object here when gathering enchantment level from an enchantment (presumably this enchantment already has a namespacedkey)

#

I would think newly registered enchantments to be the only ones getting "new" namespacedKeys

surreal peak
#

no kotlin :(

junior holly
#

This would still return a new key object

#

You could cache in a simple list

tall plover
#

oh no

#

yea, just realize

surreal peak
#

we men solve it with @Contract(pure=false)

junior holly
tall plover
junior holly
#

Once per instance of customEnchant

surreal peak
#

static importing plugin instance

tall plover
#

I should do this too lol

tall plover
junior holly
#

Not something you usually see thats for sure

surreal peak
#

dEpEnDeNcY iNjEcTiOn

#

someone wants to extend your plugin, nope they cant without modifying getInstance

#

well you get it (i hope)

tall plover
junior holly
#

Just a bit

tall plover
surreal peak
#

make a method for that?

junior holly
#

^

#

the bloat

tall plover
#

bloat?

surreal peak
#

ever heard of bloatware

tall plover
#

nope

junior holly
tall plover
surreal peak
#

i mean its just gross and pollutes your own with unnessecary things

junior holly
surreal peak
#

duplicated code, code you dont need and such

#

In computer programming, code bloat is the production of program code (source code or machine code) that is perceived as unnecessarily long, slow, or otherwise wasteful of resources. Code bloat can be caused by inadequacies in the programming language in which the code is written, the compiler used to compile it, or the programmer writing it. Th...

tall plover
#

oh

#

and what's the code i'm duplicating?

surreal peak
#

well creating the key, the container.set call, the getInstance

tall plover
#

ooh

#

so you mean creating methods for that?

surreal peak
#

could do java <T> void register(String key, PersistentDataType<T>, T data)

#

or how that looks in java, my brain is fried by kotlin generics

junior holly
#

One of the biggest OOP things is abstraction, when you start to understand it a bit better you realize that some functions could have been turned into single line functions rather than a whole method filled with duplicated code

#

Everything is an object

tall plover
#

Yea, i haven't really looked into abstraction

dense leaf
junior holly
#

So when creating a custom enchantment, the key can be created with it then registered, this allows some paths for server ops to create their own enchantments and whatnot

dense leaf
#

also why not use the 1.21 api for that

junior holly
#

That being said, you'll still probably want some default enchantments to show the structure, it really depends on if you want that sort of QOL... could be handled through like a yaml or ingame just depends what you are up for

tall plover
#

I'll try what you have told me, thanks

junior holly
#

These are keys to abstraction

tall plover
#

some resource or video I can look to improve?

junior holly
#

Full tutorial for using Generics in Java!

☕ Complete Java course:
https://codingwithjohn.thinkific.com/courses/java-for-beginners

Generics in Java can be very confusing for beginner Java learners. Generics are one of the coolest features in Java, but the syntax may not make a lot of sense at first.

In this beginner's Java tutorial video, we'...

▶ Play video
tall plover
#

thanks

junior holly
#

What are abstract classes and methods in Java, and how and why would you use them?
Also, what's the difference between an abstract class and an interface?

Abstract classes can seem like a wacky, complicated Java concept, but they're pretty simple. We'll explain them in just a few minutes in this beginner Java tutorial video lesson.

How do I ma...

▶ Play video
junior holly
late smelt
#

I just have static fields for my namespaced keys

junior holly
round fossil
#

getRegistry() should be annotated with UnmodifiableView

#

Maybe its ImmutableView idr

#

Consider using a util class to assert invariants on incoming arguments

#

For example Preconditions::checkArgument or Objects::requireNonNull

junior holly
#

Could you elaborate on that a bit more?

junior holly
round fossil
#

ah so invariants just mean conditions

junior holly
#

Ohhh ok gotcha

round fossil
#

assert means check that the conditions are valid/satisfied, in ur case non null

junior holly
cobalt trellis
#

It's UnmodiableView

#

That being said, make sure you use the normal annotations artifact

#

The annotations-java5 artifact does not include it

junior holly
#

I have had little practice with annotations, where do I configure this?

cobalt trellis
#

In you maven's POM

junior holly
#

I assume latest for this is fine?

round fossil
#

Yup

#

And u can scope it to provided

#

since annots dont have to be there at runtime

junior holly
#

I really need to learn more about maven kek

round fossil
#

Or GrAdLeEeEEEEeeeee 🐘

cobalt trellis
#

I personally use scope = provided and optional = true (which is equivalent to gradle's compileOnly configuration), in order to not mess with transitive deps

junior holly
#

Only project I have with gradle is my netty practice I did with retro

round fossil
#

Eh I mean gradle is best of them all if u need a customized work env setup

#

but like

#

its not good

junior holly
#

<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>24.1.0</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>

This works yeah?

clever crag
#

? 🙂

round fossil
junior holly
#

Ok let me go do the null checks better rq

#

Did you have any other suggestions?

round fossil
#

Nah not really, i mean there’s not a lot of code to discuss lol

junior holly
#

Is there anything that might be beneficial to add?

round fossil
#

Ig ur javadoc skills

#

but that comes with time

clever crag
junior holly
round fossil
cobalt trellis
# round fossil its not good

Gradle's only weakness is it's forwards and backwards compatibility - or rather said, the lack thereof.
If it had that, it'd be great. But I'd still stay that gradle (like maven) is quite good, but I can mainly say that because I've used other buildsystems in the past

round fossil
#

When you start to consider ownership, deferred population of entries, multithreading, serialization and deserialization of entries over file IO and network IO, versioning, reverse lookups etc nuclearkat

junior holly
#

ok ok I get it

round fossil
#

The fact that we had to include our own shading and relocation plugin is just insane

#

for years

junior holly
#
@Override
    public T get(String key){
        Objects.requireNonNull(key, "Key cannot be null");
        return this.getBackingMap().get(key);
    }```
Should I keep the if (object == null) check here?
round fossil
#

ofc it makes sense cuz in the real world its rarely the case where u shade and relocate a standalone jar that doesnt have a proper manifest etc

cobalt trellis
#

Oh, not being able to define custom variants is another gripe of mine (or rather said, only through gradle plugins, but not via the buildscript), but I'm probably one of 0.1% of people that actually need/want to use gradle variants

round fossil
#

but still, it shouldn’t be so hard as to having to apply third party plugins

round fossil
#

U can have ur own class for it

#

Its just that u kinda wanna boil down the verbosity of checking incoming arguments are valid

junior holly
#

Is that needed if it's already written into the abstract registry methods?

round fossil
#

wdym

junior holly
#

Objects.requireNotNull already means the key/values can't be null so moving these to a util class provides what benefit is what I'm trying to get at

round fossil
#

oh I mean like

#

class Asserts {
static void notNull(Object o) {
if (o == null) throw new NullPointerException();
}
}

#

U just have ur own instead

#

and use that

junior holly
#

Oh right

#

Gotcha

cobalt trellis
#

What's the problem with using the JDK-provided classes here?

round fossil
#

There’s no problem with using it

#

but its often more flexible to just have ur own, lets say u wna inject a logger to it for debugging, or whatever, if i use preconditions, verify or objects the only issue is that I’d have to use some stupid tools to do that

cobalt trellis
#

Also, I'd personally annotate the registry keys argument as @NotNull if you perform the null check here

round fossil
#

^

#

That’s true, or have like a @ArgumentsNonNullByDefault type of annot

#

I know some annot libs provide those

cobalt trellis
#

I personally don't like those as eclipse doesn't know too many nullability handling annotations

junior holly
#

Good thing I use intelliJ

round fossil
#

lol

round fossil
#

and other known big annot libs

cobalt trellis
#

It only knows it's own null annotation handling library

round fossil
#

@DefaultQualifier(NotNull.class) 😄

#

bru lol

#

monopoly

cobalt trellis
#

So Nullability, NonNull and NonNullByDefault

round fossil
#

NonNullByDefault looks good enough

cobalt trellis
#

Well you can configure it, so it's not too much of a problem

round fossil
#

btw geol I got a completely off topic question for you

junior holly
#

what's the difference between NotNull and NonNull?

cobalt trellis
#

none

round fossil
#

Nothing kekw

junior holly
#

oh kek

cobalt trellis
junior holly
#

I just saw it while I was typing @No kek

round fossil
#

Dou know any editor or extension in any ide that lets me take a decompiled class, edit it and generate me the edits by a set of mixins?

cobalt trellis
#

That unlikely exists plainly because mixins are too case-by-case dependent

round fossil
#

Yea true

#

I would really wanna attempt writing such a program

#

think it’d very useful, just was curious if one already existed

cobalt trellis
junior holly
#

Or is that lib specific?

cobalt trellis
#

Yeah, it's the API providers that need to define that

junior holly
#

Ah

cobalt trellis
#

You could manually exclude the dependency, but that is a little bit overkill

junior holly
#

I am not really bothered by it

cobalt trellis
round fossil
#

Yea it mostly auto completes suggestions

junior holly
#

Also, intelliJ is yelling at me here

round fossil
#

When typing out the long names of classes and method signatures

junior holly
round fossil
#

void

junior holly
#

oh

round fossil
junior holly
#

It's 5 am man

#

I'm trying my best

round fossil
#

12 am for me :P

cobalt trellis
#

public void unregister(@NotNull String key) { is what you should be doing instead

junior holly
#

I've only been awake 22 hours now

cobalt trellis
#

That being said, you might need to kill the default annotations-java5 library from the classpath as it has slightly different semantics when it comes to NotNull and Nullable

junior holly
#

Do I find that in proj struct?

cobalt trellis
#

nah, you need to exclude the dependency, it's a bit complicated so we'll only really do that once you need to annotate a type and annotations-java5 forbids you from it (on the other hand, you probably could just reorder the dependencies in the pom methinks)

junior holly
#

Do you mean generic in this case or just any type?

cobalt trellis
#

The type target includes generics, but also variable declarations

tall plover
#

I've made this code and was wondering if it is great and doesn't affect that much the performance of the server

#

what do you think?

surreal peak
#

whats even the point of that useDatabase

tall plover
surreal peak
#

use inheritance or smth

tall plover
#

if useDatabase = true | database

surreal peak
#

and youre never closing your statements

tall plover
tall plover
surreal peak
tall plover
#

hmm

#

I could do that

tall plover
surreal peak
#

you arent saving either if you do a config.set

tall plover
#

oh lol

#

frgot that

#

just add it there

surreal peak
#

use a try with resources

tall plover
#

oh

lyric stump
#

Not a huge plugin, just wanted to know if I could improve something.

surreal peak
#

make folder names lowercase

#

extend TabExecutor instead in your commands if you want both executor and tabcompletor

#

if an user types command aaa they will get the reload completion either way

#

use StringUtils.copyPartialMatches

#

look at its internals

#

also public mutable variables, hell na

#

saveDefaultConfig() instead of this

#

tf is this nesting

#

so thats had pyramids were built then

junior holly
#

The aliens didn't do it, some dev just wasn't following proper oop

surreal peak
#

copied metrics class contains some nonsense too

dense leaf
surreal peak
#

idk

dense leaf
#

the commands are atleast somewhat organised

jagged rock
#

You seem to toss everything in your main class, repeat function calls all the time (getConfig()), get values from the config instead of caching them into fields, the list goes on

#

The habits applied are wildly inconsistent too (guard clauses deeply nested)

#

I'd give it maybe a 3/10

lyric stump
lyric stump
#

@jagged rock
Can you help me with the nesting?
I am so lost.

sly jackal
#

its just instead of if condition you have if not condition return or continue

woeful pasture
#
if(thing){
 DoThings()
}

Guard clauses

if (!thing){
 return
}
doThings();
surreal peak
#

put that return on the same line

jagged rock
dense leaf
#

!?

#

did you mean a semicolon or something

alpine anvil
#

no

#

this should be inverted

dense leaf
#

o yea

#

smh miles

woeful pasture
#

Gimme a break

alpine anvil
#

nuh uh

late smelt
#

It is also missing a semicolon :p

alpine anvil
#

trueeeeeeeee

woeful pasture
late smelt
#

```java
if(thing){
DoThings()
}
```

Guard clauses
```java
if (!thing){
return
}
doThings();
```

#

Exposed

woeful pasture
late smelt
#

It’s called copy text in the mobile app

#

You spoon

remote kiln
dense leaf
#

mongo 💀

sleek shard
sleek shard
remote kiln
#

uh

#

yes

sly jackal
#

why double getter

surreal peak
#

why no kotlin

remote kiln
surreal peak
#

because?

dense leaf
#

ignorance

remote kiln
dense leaf
#

why

remote kiln
#

personal preferences

surreal peak
#

buddy never used c

round fossil
#

So fuck that lombok horse you rode in on, do us a favor and delombok ur code

woeful pasture
alpine anvil
#

holy shit you actually said the normal person keybind

woeful pasture
alpine anvil
#

i was going for the fact you use vsc keybinds

woeful pasture
#

I changed to some vsc for a few things but it's mostly eclipse

gilded gate
surreal peak
#

end your plugin class name in Plugin

#

and why use an instance of ConfigUtils, a real utility class is stateless, which isnt the case here

#

inheritance

#

not sure if you want to store punishments in a list

#

do not share mutable collections

#

why use final in parameters

dense leaf
#

couldn't be me

surreal peak
#

why CommandAbstract and not AbstractCommand

#

these sound pretty vague to a new reader

sly jackal
#

why end with Plugin, is that the style guide?

surreal peak
#

could use Map.of

surreal peak
#

if someone didnt know we were working with plugins, they would have no clue

sly jackal
#

yeah true I guess

#

imma keep that in mind

surreal peak
#

take a look at StringUtils.copyPartialMatches

#

why BanArg if it extends CommandAbstract?

#

and i would inject the punishment manager instead of the plugin instance, you dont even need it

#

theres not even a reason CommandAbstract is an abstract class

sly jackal
#

its in the name, duh

#

xD

surreal peak
#

this feels like a usecase for a Punishment::fromX factory method, also mismatched responsability

sly jackal
#

I would probably rename it to BaseCommand or something then

surreal peak
#

same thing: inject config utils instead then 🤷‍♂️

#

also why does class MySql not extend Database or smth

#

wait MySqlData does, what kind of name is that

#

and return something in loadData()

#

maybe a boolean, maybe a future if you decide to do it async

#

like that MySqlData class should be renamed to just MySql[Database] and that MsqlData class shouldnt even exist then, put everything in that one class

#

and i dont really think its the responsability of a data loader to load the data into the punishmanager that it holds, it should just return it imo, and the caller decides whether it wants that data in the punishment manager

#

i think you can just close it without writing, set truncate bit

#

time for dinner now

#

Some good bacon hehehe

night knoll
surreal peak
#

And add fewer salt

#

Shall we make this a cooking channel?

wind stag
#

https://github.com/eliottlebot/thetowersplugin

Hello, like I said in the main channel, I'm new to making plugins, and i coded a The Towers plugin to play with my friends. I have some basics in Java coding, but I wanted to know if my plugin is well structured (i don't think so), I'll take any suggestions. Thanks !

woeful pasture
surreal peak
#

my turn

woeful pasture
surreal peak
#

GameManager::startGame is just a piece of garbage

#

uh oh constructive feedback

woeful pasture
surreal peak
#

split it up into functions cuz theres so much duplication

#

you cloned it?

#

also instantiating pointless bukkitrunnables, use the scheduler instead

#

might even want to write proper classes for those tasks

woeful pasture
#

For beginners I think it's actually much more constructive to point out specific things and explain why instead of lazily throw things out. It's likely they don't even know the scheduler exists or don't know why lambdas are better

#

I'm on my phone and at work if needed I'll actually thoroughly give more feedback later

surreal peak
#

oh youre at work

surreal peak
#

end user visible messages

wind stag
#

like this one ? ```
Bukkit.broadcastMessage(ChatColor.GOLD + "[The Towers] " + ChatColor.GRAY + "Annulation du lancement");

surreal peak
#

y

wind stag
surreal peak
#

use functions that explain whats going on

wind stag
#

instead of writing big blocks of code ?

surreal peak
#

use a countdown task or smth instead of spawning random bukkitrunnables

#

and you forgot a return here

#

also so much duplicated code

#

for both teams

wind stag
#

yeah I used them because I thought it was easy but if it is not optimized i'll try to use schedulers

surreal peak
#

its literally the same thing but its merely a syntax difference

#

just passing a callback or an instantiated task class is way cleaning that randomly doing new BukkitRunnable() { some huge pile of code }.run()

wind stag
#

are schedulers less resource-intensive?

surreal peak
#

literally the same thing, scheduler simply spawns a task

wind stag
#

ok so for example i'll create a runnable class that starts the game

surreal peak
#

ye

wind stag
#

i see

surreal peak
#

its cleaner and separates different parts of your code

wind stag
#

yeah

surreal peak
#

its just advice do with it what you want

wind stag
#

i take every advice i can, i know my code can only be improved

#

thanks!

desert ore
surreal peak
#

fuck its java

desert ore
#

lmao

surreal peak
#

example doesnt even compile

dense leaf
#

kek

desert ore
#

I forgor to finish it dw

#

hope you don't mind

#

it's all written on gh and I have never tested it lol 💀

surreal peak
#

there a reason PacketInstance isnt a record/ has all its fields final?

desert ore
surreal peak
#

and id probably make packet registry a singleton withoit getinstance

desert ore
#

understandable

surreal peak
#

putifabsent

desert ore
#

there is putIfAbsent???

surreal peak
#

BiConsumer<MSG, Supplier<PacketContext>>

desert ore
#

that's just derived from forge

#

but I can change that

surreal peak
#

so if forge jumps from a bridge, youll also jump my mom would say

desert ore
#

lol

desert ore
surreal peak
#

read the docs

#

whoops

desert ore
#

also, what do you think of dynamically generating a Identifier/ResourceLocation from the class name instead of prompting the user to think of their own?

surreal peak
#

make it optional

desert ore
#

hmm, well, I think I'll do that later

#

for now, make a record and get rid of the supplier, right?

simple hamlet
surreal peak
#

why is it PLUS and ULTIMATE if its simple

late smelt
#

Why isn’t it the deluxe edition

#

Or goty edition

simple hamlet
#

👍

#

Couldn't find any other name

simple hamlet
dense leaf
#

hider plus pro max deluxe extreme edition

simple hamlet
#

With price of $420.69

#

And no special feature

#

Buy my plugin and getout...

inland inlet
surreal peak
#

gui shouldnt be a listener, separate responabilities

random yacht
#

Just an immediate thing I can pickout... getGUI(EnchantType, ItemStack) Is there any reason this isn't done in EnchantType in some capacity? You could save yourself a switch

#

If it's an enum, a Function<ItemStack, EnchantGUI> in your EnchantType constructor would be fine, you could pass in SwordEnchantGUI::new, LeggingsEnchantGUI::new, etc. etc.

#

If it's a class, even better. Make an abstract method

#

Oh it's in a switch, of course it's an enum lol (unless you're using Java 21 features 👀)

inland inlet
#

I changed the function

surreal peak
#

fuck java 8, was gonna say methodhandle

inland inlet
#

never heard of it

surreal peak
#

what type is enchantGUI? class?

inland inlet
#

abstract class

surreal peak
#

ig what choco said also applies here then

inland inlet
#

How so?

surreal peak
#

why not make it abstract?

why not make it protected?

why not get rid of it?

inland inlet
#

make what abstract?

surreal peak
#

like whats the point of it

#

ah full code is in the paste

inland inlet
#

the point of having the class be abstract?

inland inlet
surreal peak
#

ah wait thats another class

inland inlet
surreal peak
#

god

#

hold a Tag instead

inland inlet
#

Tag?

surreal peak
#

check the api, their are tags for things like axes, pickaxes, hoes, whatever

inland inlet
#

rly?

surreal peak
#

yes so replace getEnchantType with tag.isTagged(material) ? enchanttype : continue

#

you get the idea

#

enum EnchantType { Shovel(ShovelThing.class, Tag.SHOVELS_OR_SMTH) }

inland inlet
#

Then id have to create a new Tag

surreal peak
#

wdym

inland inlet
#

Theres no such tag as SHOVEL

#

afaik

random yacht
#

Yeah the tags are fairly limited

surreal peak
#

ITEMS_SHOVELS

#

just rhe vanilla stuff

inland inlet
#

From what package is the tag

surreal peak
inland inlet
#

#ImSorryImOn1.8

inland inlet
#

yea

#

seems about right

surreal peak
#

at that point id just fork cb and implement it all myself

inland inlet
#

Thats why im justing having a list of all the materials under that category

surreal peak
#

oh no grandma

cobalt trellis
#

Oops, meant to quote the post above it, whatever

late smelt
#

Does java 8 not have Function

inland inlet
#

Whats method handle tho

cobalt trellis
#

Reflection but a bit different

cobalt trellis
inland inlet
#

ty

late smelt
#

So Choco’s original suggestion still stands :p

dense leaf
#

why are you using the console sender btw

alpine anvil
dense leaf
#

why not biconsumer

cobalt trellis
#

Why BiConsumer of all things?

#

Will you do a BiConsumer<ItemStack, AtomicReference<EnchantGUI>> or what?

dense leaf
cobalt trellis
#

What

#

Lemme guess: Closures?

dense leaf
#

i would just do block: (ItemStack, EnchantGui) -> Unit in kotlin

#

which is effectively a BiConsumer

cobalt trellis
#

Yeah, but you want an ItemStack go in, EnchantGui go out - not ItemStack and EnchantGui go in, nothing go out.

dense leaf
#

ohhh

#

block: (ItemStack) -> EnchantGui then

clever crag
#
public class DatabaseAdapter {
    public static DatabaseSettings fromConfig(ConfigurationSection section) {
        String path = "database.sql.";
        return new DatabaseSettings(section.getString(path + "host", "localhost"), section.getString(path + "port", "3306"),
        section.getString(path + "database", "simplepenalty"), section.getString(path + "username", "root"), section.getString(path + "password", ""),
        section.getString(path + "table-prefix", "simplepenalty_"), SQLDialect.valueOf(section.getString("database.type", "SQLITE").toUpperCase(Locale.ENGLISH)),
        section.getStringList(path + "properties").stream().collect(Collectors.toMap(str -> str, str -> section.getString(path + "properties." + str, ""))));
    }
}
#

Is it correct or i need to remove static and do my class singleton?

surreal peak
#

looks awful to read

#

and why is a DatabaseSettings factory method located in an adapter class?

dense leaf
#

please click ctrl-alt-l twice

#

tyvm

random yacht
#

For long constructors like that I tend to like doing this type of formatting:

public class DatabaseAdapter {
    public static DatabaseSettings fromConfig(ConfigurationSection section) {
        String path = "database.sql.";
        return new DatabaseSettings(
            section.getString(path + "host", "localhost"),
            section.getString(path + "port", "3306"),
            section.getString(path + "database", "simplepenalty"),
            section.getString(path + "username", "root"),
            section.getString(path + "password", ""),
            section.getString(path + "table-prefix", "simplepenalty_"),
            SQLDialect.valueOf(section.getString("database.type", "SQLITE").toUpperCase(Locale.ENGLISH)),
            section.getStringList(path + "properties").stream() // I prefer stream() on the same line, but you can put it on the next
                .collect(Collectors.toMap(
                    str -> str, // You can use Function.identity() here if you wanted instead. I sort of prefer the quick readability
                    str -> section.getString(path + "properties." + str, "")
                )
            )
        );
    }
}
#

Makes reading things a little bit easier to follow. Though I think at this point it might be worth investigating a proper builder pattern, especially if your settings object is immutable. That way you can have a more readable way to construct your object... something like this instead:

public class DatabaseAdapter {
    public static DatabaseSettings fromConfig(ConfigurationSection section) {
        String path = "database.sql.";
        return DatabaseSettings.builder()
            .host(section.getString(path + "host", "localhost"))
            .port(section.getInt(path + "port", 3306)) // Make this a getInt(). Just makes more sense
            .database(section.getString(path + "database", "simplepenalty"))
            .username(section.getString(path + "username", "root")) // Maybe join this and password() into credentials(String, String)?
            .password(section.getString(path + "password", ""))
            .tablePrefix(section.getString(path + "table-prefix", "simplepenalty_"))
            .dialect(SQLDialect.valueOf(section.getString("database.type", "SQLITE").toUpperCase(Locale.ENGLISH)))
            .properties(section.getStringList(path + "properties").stream()
                .collect(Collectors.toMap(
                    Function.identity(),
                    str -> section.getString(path + "properties." + str, "")
                ))
            )
            .build();
    }
}
#

I guess my last recommendation, instead of prepending a path, you can get a configuration section with the path.

public class DatabaseAdapter {
    public static DatabaseSettings fromConfig(ConfigurationSection config) {
        ConfigurationSection dbConfig = section.getConfigurationSection("database.sql");
        return DatabaseSettings.builder()
            .host(dbConfig.getString(path + "host", "localhost"))
            .port(dbConfig.getInt("port", 3306))
            .database(dbConfig.getString("database", "simplepenalty"))
            .username(dbConfig.getString("username", "root"))
            .password(dbConfig.getString("password", ""))
            .tablePrefix(dbConfig.getString("table-prefix", "simplepenalty_"))
            .dialect(SQLDialect.valueOf(config.getString("database.type", "SQLITE").toUpperCase(Locale.ENGLISH)))
            .properties(dbConfig.getStringList("properties").stream()
                .collect(Collectors.toMap(
                    Function.identity(),
                    str -> dbConfig.getString("properties." + str, "")
                ))
            )
            .build();
    }
}
#

Okay I'm done spamming lol

clever crag
#

thanks

#

renamed DatabaseAdapter into DatabaseSettingsFactory

    public static DatabaseSettings fromConfig(ConfigurationSection section) {
        ConfigurationSection dbSection = section.getConfigurationSection("database.sql");
        return DatabaseSettings.builder()
                               .host(dbSection.getString("host", "localhost"))
                               .port(dbSection.getString("port", "3306"))
                               .database(dbSection.getString("database", "simplepenalty"))
                               .username(dbSection.getString("username", "root"))
                               .password(dbSection.getString("password", ""))
                               .tablePrefix(dbSection.getString("table-prefix", "simplepenalty_"))
                               .sqlDialect(SQLDialect.valueOf(section.getString("database.type", "SQLITE")
                                                                     .toUpperCase(Locale.ENGLISH)))
                               .properties(dbSection.getConfigurationSection("properties")
                                                    .getValues(false).entrySet().stream()
                                                    .collect(Collectors.toMap(Map.Entry::getKey,
                                                                              value -> value.getValue().toString()))
                               )
                               .build();
    }
surreal peak
#

why is a database factory producing settings and not databases

clever crag
#

i should rename it into DatabaseSettingsFactory?

random yacht
#

You could also put that method in DatabaseSettings itself. Nix the factory all together 👀

#

DatabaseSettings.fromConfig()

surreal peak
#

thats what i was implying

clever crag
#

is it correct?

public class NumberFormatException extends RuntimeException {
    public NumberFormatException(CommandSender sender, String message) {
        Messages.NUMBER_FORMAT.send(sender, message);
    }
}
    int amount;
    try {
        amount = Integer.parseInt(args[4]);
    } catch (RuntimeException e) {
        throw new NumberFormatException(sender, args[4]);
    }
random yacht
#

I mean it's unconventional. What's wrong with just this?

int amount;
try {
    amount = Integer.parseInt(args[4]);
} catch (NumberFormatException e) { // The one Java provides by default and throws on parseInt()
    Messages.NUMBER_FORMAT.send(sender, args[4]);
    return true; // Presumably this is in a command sender
}
surreal peak
#

java has that class already

#

and that constructor is clearly a mismatched responsability

random yacht
#

I mean meh. You're sort of abusing exceptions to wrap a message send call

#

Exceptions are meant to be used as "I cannot possibly recover from this"

surreal peak
#

^

late smelt
#

Ints.tryParse my beloved

rancid fern
#

What's that from?

#

C#?

late smelt
#

Guava

#

It returns an Integer wrapper type

rancid fern
#

nice

surreal peak
#

out params

late smelt
#

This isn’t C#

surreal peak
#

too bad

random yacht
#

I'm more of a NumberUtils.toInt() type guy

night knoll
#

In js you do: +"5"

desert ore
#

Can we get an IntOptional

#

Optional, but for primitive int

random yacht
#

You mean OptionalInt? 👀

#

That's existed since 1.8 you silly goose

desert ore
#

it exists????

#

That's great

#

Can we get an string to int parser that uses OptionalInt

random yacht
#

You could definitely wrap that yourself

#
public static OptionalInt tryParse(String input) {
    try {
        return OptionalInt.of(Integer.parseInt(input));
    } catch (NumberFormatException e) {
        return OptionalInt.empty();
    }
}```
desert ore
#

Isn't throwing and then catching an exception kinda expensive tho

random yacht
#

So is printing to the output stream

#

Everything is expensive :p

desert ore
random yacht
#

What matters is how relatively expensive it is

desert ore
random yacht
#

I dunno. Are you doing database queries? If so, your exception handling isn't gonna matter lol

#

Besides, there's literally no other way to do it unless you reimplement parseInt() I guess

rancid fern
#

Guava reimplements it uwu

late smelt
#

Yeah use that with the ofNullable wrapper :p

wintry fern
clever crag
#

and .db file format

charred forge
hasty lotus
hasty lotus
#

oh nvm

#

I'm dumb lmao

charred forge
hasty lotus
#

Yeah ic

#

Do you use checker framework or annotations? Useful for someone that may use your library to check what methods could return null

charred forge
#

I use the jetbrains ones, because intellij

#

just don't look at the convaluted item library that powers the cross-platform icons :3

hasty lotus
#

https://github.com/TheNewEconomy/TNML/blob/main/Core/src/net/tnemc/menu/core/constraints/impl/IntConstraint.java You can use Ints#tryParse here since catching the exception might be expensive.

https://github.com/TheNewEconomy/TNML/blob/main/Core/src/net/tnemc/menu/core/constraints/impl/DoubleConstraint.java Same here but for Doubles#tryParse

You should use final on method parameters too (even when it's obvious that the var won't change, cause for the future). I honestly just have an Intellij plugin insert final whenever it's possible for easier readability. It applies not to just fields but everything tbh

For some of your methods, consider creating more variables for readability. For example, https://github.com/TheNewEconomy/TNML/blob/4c22d6fb167f0577e7b2637f3f0cf1ead58ff252/Core/src/net/tnemc/menu/core/icon/action/impl/SwitchMenuAction.java#L54 maybe create a Player variable so you don't have to call handler.player() three times.

Honestly for the most part my suggestions are just tiny changes and the code looks fine.

charred forge
#

cheers

#

the constrains feature is probably something I'll end up removing, it's kinda meh, final on params definitely nice to have added the variable part I don't even remember what I was thinking at the time XD

winged blaze
#

It gets messy and hard to read

hasty lotus
#

But I don’t agree with how it gets hard to read. It’s good knowing that the variable won’t be reassigned somewhere else

round fossil
#

its true that final is verbose by nature to use, buut I think it still adds readability and reduces bug-proneness which is good

random yacht
#

They should really be final by default and then you'd have to add mutable or something to make it, well, mutable :p

#

Or, hear me out, stick with the same vibe as non-sealed...

#

non-final

desert ore
random yacht
#

A few languages are immutable by default yes

#

But I think that's everything

#

I just mean local vars

#

I hope, but I sincerely doubt it

surreal peak
#

just use kotlin

dense leaf
#

use serde::Serialize as Serial my beloved

desert ore
#

#define System.out.println println when

dense leaf
surreal peak
dense leaf
random yacht
#

The day Java adds preprocessor statements is the day I kill myse-

#

Actually one does exist already lol

#

It's terrible. Please don't use it

#

But it exists

dense leaf
dense leaf
#

kotlin

#

it's a thing

surreal peak
desert ore
#

but imagine just import as

#

import * as gay

dense leaf
surreal peak
#

yes

dense leaf
#

oh damn

random yacht
dense leaf
#

probably

desert ore
#

I think it was js where you could do import * from './request.js' or something like thag

dense leaf
#

yea

#

js / python 🤢

surreal peak
#

what

#

s wrong with python

dense leaf
#

slow asf, indent based

#

interpreted, dynamically typed

surreal peak
#

python isnt dynamically typed

desert ore
dense leaf
#

you can add type annotations but it doesn't use them by default

surreal peak
#

typescript is a linter

#

always will be

desert ore
#

typescript is great

dense leaf
#

typescript doesn't change the fact that js is ass

#

real

dense leaf
desert ore
#

I loved typescript

#

Besides transfering data

dense leaf
#

#

i ain't a java addict

#

@vital jasper is

desert ore
surreal peak
#

this how it works?

desert ore
#

I'm taking about how you have to unsafe cast jsons to interfaces and stuff

dense leaf
desert ore
dense leaf
#

that would make too much sense ro do sry

#

ew

desert ore
#

I have

surreal peak
#

yes

desert ore
#

C# is weird, but I'd say it's okay

surreal peak
#

atleast its better than java

desert ore
#

Just another OOP language with some weird conventions

desert ore
surreal peak
#

but ive never cared enough to use it

desert ore
#

Java is pretty decent if you think about it

surreal peak
#

c on its best

desert ore
surreal peak
#

i mean odin

#

hows your lang going

desert ore
#

odin 💀

round fossil
#

C# is a bit more ergonomic than Java at least

surreal peak
#

oh no conclure joined

desert ore
#

C# is an interesting lang

surreal peak
#

ref structs uwu

desert ore
#

I've been planning to work on my terraria mod for ages, great opportunity to learn C#

surreal peak
#

have you developed some anger against a lang you dont know?

round fossil
desert ore
surreal peak
#

ill never change

#

maybe because its great

round fossil
#

😔

vital jasper
#

Java is great, TypeScript is great, JavaScript is great, Python is shit, Kotlin is shit

dense leaf
desert ore
#

Lmao

#

no language is shit

#

uhh, besides python

#

but no language is shit besides that

surreal peak
#

javascript is

#

python is nice for cross platform scripts

desert ore
#

So is kotlin

round fossil
#

idk bout typescript

#

it looks great, but eh

pine grail
#

Java > Kotlin U Java = Scala

#

idk if I got my maths writing thing right

#

but should be

surreal peak
#

im not gonna leave the user behind with some class files

round fossil
#

since Kotlin was (partly) created bcuz of lacking features from both Scala and Java?

surreal peak
#

kotlin > java and i cant form an opinion on scala

#

scala looks a bit cringe tho but im happy to learn new things

pine grail
surreal peak
#

oh

pine grail
#

Anyways

surreal peak
#

i also should try it out then

pine grail
#

scala is goated

#

it's a bit weird

#

you need to get used to it

surreal peak
#

i still dont get what this word means

pine grail
#

and learn how it works otherwise your code is slow as shit

pine grail
surreal peak
#

sounds quite like the opposite

pine grail
#

anyways if you learn it you can make very safe, beautiful and (relatively) fast code

surreal peak
#

saying "fast" on interpreted langs has no meaning to me

pine grail
#

there is scala native

desert ore
#

goat = greatest of all time

surreal peak
#

now read that again

pine grail