#Problem with list on super classes

381 messages · Page 1 of 1 (latest)

weary sphinx
#

Let's say that A extends B
So is it possible to convert a LIst<A> to a List<B> in the fastest way possible ?
Example :

public class Entity ...

public class Player extends Entity ...
public class Enemy extends Entity ...

List<Enemy> enemy_list = new ArrayList<Enemy>();
List<Entity> enemy_list_as_entities = ...  ?? // <- I want this to be the enemy_list but as entities and not as Enemies

Please try to ping me if you have the answer
Thanks

naive lindenBOT
#

This post has been reserved for your question.

Hey @weary sphinx! Please use /close or the Close Post button above when you're finished. Please remember to follow the help guidelines. This post will be automatically closed after 300 minutes of inactivity.

TIP: Narrow down your issue to simple and precise questions to maximize the chance that others will reply in here.

glossy basin
#

I mean, you're trying to "convert" an empty list.
If you want to convert a non-empty list, here is the fastest:
List<Entity> enemy_list_as_entities = new ArrayList<>(enemy_list);
@weary sphinx

#

If you want an unmodifiable view of the list, then:
List<Entity> enemy_list_as_entities = Collections.unmodifiableList(enemy_list);

#

Of course, in such a case, one should wonder why do you want to do that and why can't you use the original list instead.

pure sedge
#

Java might be able to directly cast all elemnts within the list to it too

#

(List<Entity>) enemy_list;

#

shoudl work in theory

#

but I am not sure how smart the Java casting is

pure sedge
#

you are reallocating a new array

#

and then moving all the pointers to the new array

#

casting it just changes the identifer

#

I do not know why you would want to upcast though

#

mostly you downcast

#

to a subclass

#

and according to what I read on the topic, the JVM should be able to optimise the casting away and predict what is going on...

glossy basin
# pure sedge is it the fastest though...

Depends on what are the constraints you're allowed to ignore.
In your solution, you're making so it is possible to add Entities to a List<Enemy>. That is a type safety violation. Usually you do'nt want that.

pure sedge
#

not safe

#

casting always can go wrong and throw an exception

glossy basin
#

Well the fastest is to not do it at all. There are a number of times when the results will be unsatisfactory, but they asked for fast, not working

pure sedge
#

-_-

#

benchmark the two solutions

#

with a small and large data set

glossy basin
#

You must always consider the constraints

pure sedge
#

and then see how they stack up!

pure sedge
#

casting is just changing the reference

glossy basin
#

Yes, but it satisfies every use-cases. I also spoke of another way, which is just as fast as yours, but adds the constraint that the resulting list is unmodifiable

#

So: you must always consider the constraints

pure sedge
#

you cant say what is faster or not without benchmarking it

glossy basin
#

Beside they asked for a conversion. A conversion would usually be independant to its original source. With your solution modifying the source modifies the conversion

pure sedge
#

JVM will always optimise things out

glossy basin
#

So: you must always consider the constraints

pure sedge
#

you got to figure out what it expands to when it is optimised into machine code at runtime

#

and that takes trail and error

pure sedge
#

it will work for A and B

glossy basin
#

Depends on what counts as working

#

If you intend to do nothing, then the fastest is to not do anything, not your solution

#

If you intend to do things, then your solution may or may not work

#

So: you must always consider the constraints

pure sedge
#

@glossy basin why does it feel you are trying to educate me

#

I am not the one who is asking for help

#

I provided a solution which may work, cause I didn't test it

glossy basin
#

I am trying to explain why your solutions isn't necessarily good. That it sounds like educating you rather than anyone who wouldn't already know that, is an effect I'm not trying to achieve, but isn't a surprise to me either

pure sedge
#

you allocate a new arrya

#

class instantiation takes a lot of time

glossy basin
#

I keep saying it depends on the constraints. Of course I can't know if my solution is perfect if I don't know what constraints matter

pure sedge
#

your second approach calls a function which you have no clue how it works, therefore you do not know the efficiency based on it either

glossy basin
#

I litterally gave two solutions

pure sedge
glossy basin
pure sedge
glossy basin
#

I already said. My second solution is faster than my first. However, it requires that you don't want to modify the lists, while my first solution will work even if you want to do that.

pure sedge
#

you could in theory implicitly cast it

glossy basin
#

It has the same drawbacks as my second solution, but doesn't make it clear that it is type-unsafe

pure sedge
#

List<Entity> entities = enemyList;

pure sedge
#

variable names should be camel case

pure sedge
#

but as its implicit I am unsure how well the JVM will deal with it

#

or even if you can upcast implciitly

glossy basin
pure sedge
#

this is not AOT compiled

#

bytecode is not perfect, the JVM still has to do a lot

glossy basin
#

I meant on the part you're talking. On that part the JVM does nothing.

pure sedge
#

well implicit there shouldnt be any checking

glossy basin
#

You can't upcast implicitly as, as I said, that would allow you to add Entities to a List<Enemy>. But using explicit casts you can do that. These explicit casts announce that you don't care that you're breaking type-safety. As far as the JVM is concerned, that's just assigning an object to a new local variable, which is, do nothing.

glossy basin
#

I don't know what you want. That you can't do that, just try and the compiler will let you know it refuses to compile that.
That explicit casts announce that you don't care that you are breaking type safety, just try and the compiler will warn you about how you're breaking type safety

weary sphinx
weary sphinx
naive lindenBOT
# weary sphinx Thanks dude

If you are finished with your post, please close it.
If you are not, please ignore this message.
Note that you will not be able to send further messages here after this post have been closed but you will be able to create new posts.

weary sphinx
#

Hey the bot please let me just 10 more minutes so i can test everything

#

But thank you all

pure sedge
weary sphinx
#

What do you mean ?

#

Oh and

#

So you're saying that this is the fastest way :

public List<RawEntity> getInstancesAsRawEntities() {
        List<RawEntity> entities = (List<RawEntity>) instances;
        return entities;
    }
rare aspen
rare aspen
#

pretty sure that causes a compile error

weary sphinx
#

instances is of a class that extends rawentity

rare aspen
#

you need a new list as kyo mentioned

weary sphinx
#

Wait lemmie try...

#

Yea okay

#

Lemmie try his way then

rare aspen
rare aspen
weary sphinx
#

Ummm

#

Actually

#

Lemmie explain you all the problem to be sure to make it the better way possible

#

So lemmie explain

#

I have a class called EntityBatch :

#
public class EntityBatch <T extends RawEntity> {
    private TexturedModel model;
    private List<T> instances = new ArrayList<T>();
    ...
}
#

And basically i have other classes like Enemy or Player or House that extends RawEntity

#

So when i create them i do

#

i MEAN

#

When i create the entity batch for them i do this...

#

Wait

rare aspen
#

not sure why you'd want a List<RawEntity> for that to begin with

weary sphinx
#
EntityBatch<Enemy> enemies = new EntityBatch<Enemy>();
#

Why ?

rare aspen
#

you can use List<? extends RawEntity> to take any of the possible instances types

weary sphinx
#

I've actually tried that

#

But lemmie explain

rare aspen
weary sphinx
#

Not really

#

I searched for it in the internet but didn't find anything helpful

#

Lemmie continue

#
public <T extends RawEntity> void processEntityBatch(EntityBatch<T> entitybatch)
{
    ...
}
#

This method is from another class and takes in an entity batch

#

I want to class processEntityBatch for an enemy batch

#

For example

pure sedge
weary sphinx
#

And i want to access properties of RawEntity for each instance of the batch

rare aspen
weary sphinx
#

In this method

rare aspen
#

if you could cast then kyo would've mentioned it

weary sphinx
#

I just want processEntityBatch to take in

#

Either

rare aspen
weary sphinx
#

List<ENemy>

#

List<House>

#

...

#

Why ?

#

Yes i do

rare aspen
#

you don't

weary sphinx
#

That's for my program

#

SO what should i do ?

rare aspen
#
void <T extends RawEntity> method(List<T> list) {
  T x = list.get(0);
  // x is a subtype of RawEntity
  // you can access members of RawEntity from x
}
#

wildcards also work

weary sphinx
#

But i need the entity batch

#

Because i have other things that i didn't show

#

In it

rare aspen
#
void method(List<? extends RawEntity> list) {
  RawEntity x = list.get(0);
  // T from the List is a subtype of RawEntity
  // you can upcast T to RawEntity
}
weary sphinx
#

OHHHH

#

BUt no...

rare aspen
weary sphinx
#

Nope

#

I just want it to take in

rare aspen
#

I just want processEntityBatch to take in
List<ENemy>
List<House>

weary sphinx
#

Any

#

Oh sorry didn't express well

#

I mean

rare aspen
#

can you please make coherent sentences instead of spreading your words out into 5 messages

weary sphinx
#

Yes

#

Actually, i need this method public <T extends RawEntity> void processEntityBatch(EntityBatch<T> entitybatch) to take in any type of entity batch, either EntityBatch<Enemy> or EntityBatch<Player> or EntityBatch<Car> or any entity batch as : EntityBatch<class> where class extends RawEntity

#

Sorry for not formulating correct sentences

rare aspen
#
public <T extends RawEntity> void processEntityBatch(EntityBatch<T> entityBatch) {
  List<T> instances = entityBatch.getInstances();
  T x = instances.get(0);
  // T is a subtype of RawEntity
  // you can access members of RawEntity from x
}
#

to take in any type of entity batch
right, and that's what generics or wildcards allow you to do

#

EntityBatch<class> where class extends RawEntity
that's what EntityBatch<? extends RawEntity> or <T extends RawEntity>, EntityBatch<T> mean

weary sphinx
#

Okay then

#

But

#

That brings us to the main problem

#

I'll explain, lemmie 3 minutes

#

Here is the code of the method :

public  <T extends RawEntity> void testCollisions(Vec3f newpos, List<EntityBatch<T>> batches)
    {
        if(checkTerrainBorders(newpos))
        {
            return true;
        }
            for(EntityBatch batch:batches)
            {
                for(RawEntity instance:batch.getInstances())
                {
                    if(instance.CheckAABBCollision(instance.getCollisionBox(), newpos, collisionBox))
                    {
                        collisionBox.print("Collision");
                        return true;
                    }
                }
            }
            
        
        
        
        return false;
    }

It takes a list of entitybatch but i have two problems with it...

rare aspen
#

there is no problem here

weary sphinx
#

Actually yes...

rare aspen
#

just put in the appropriate generics

weary sphinx
#

Lemmie tell you

#

Umm

#

Nope

#

Actually just lemmie finish explaining

rare aspen
#

EntityBatch is a generic type, you didn't provide the generic so it's a raw type there

#

use EntityBatch<T>

weary sphinx
#

Justly

#

That's the problem

rare aspen
#

oh god here we go again...

#

alright then, what's the issue with it

weary sphinx
#

I want the list of entity batch batches to be a list of multi-type batches :
Example, i could pass :

List<EntityBatch> list_of_different_batches = new ArrayList<EntityBatch>
list_of_different_batches.add(new EntityBatch<Enemy> ...)
list_of_different_batches.add(new EntityBatch<Player> ...)
list_of_different_batches.add(new EntityBatch<Car> ...)
testCollisions(aVector, list_of_different_batches);

I want the list to hold any type of entity batch
Knowing that the class Enemy, Player, Car are all extending RawEntity

#

That's the problem

rare aspen
#

you can replace your generic with a wildcard then

weary sphinx
#

Where ?

rare aspen
#

but with the EntityBatch

weary sphinx
#

Ohhhh i see

#

Wait lemmie try

#
public boolean testCollisions(Vec3f newpos, List<EntityBatch<? extends RawEntity>> batches)
    {
        if(checkTerrainBorders(newpos))
        {
            return true;
        }
            for(EntityBatch batch:batches)
            {
                for(RawEntity instance:batch.getInstances()) <---- HERE
                {
                    if(instance.CheckAABBCollision(instance.getCollisionBox(), newpos, collisionBox))
                    {
                        collisionBox.print("Collision");
                        return true;
                    }
                }
            }
            
        
        
        
        return false;
    }

There's an error at where i pointed
It takes batch.getInstances() as Object and not as List<RawEntity>

#

But batch.getInstances() returns RawEntity

#
public List<RawEntity> getInstancesAsRawEntities() {
        List<RawEntity> new_instances = new ArrayList<>(instances);
        return new_instances;
    }
rare aspen
#

i left a raw type somewhere didn't i...

rare aspen
weary sphinx
#

What are you doing exactly ?

weary sphinx
#

I mean List<RawEntity> and not RawEntity

rare aspen
#

getInstances should just give you List<T>

weary sphinx
#

Oh

#

Oh damn i'm stupid

#

I used another one

#

Sorry

#

So that brings us to my first question

#

Should i use a method in entitybatch like this one :

public List<RawEntity> getInstancesAsRawEntities() {
        List<RawEntity> new_instances = new ArrayList<>(instances);
        return new_instances;
    }
#

This one does return List<RawEntity>

#

Isn't it ?

#

Then should i use this or is there any better way to accomplish it ?

rare aspen
#

getInstancesAsRawEntities is probably just unnecessary as an operation

#

wildcards are how you achieve "subtyping" with generics

weary sphinx
#

But it didn't work then

#

It wouldn't work

#

I mean

#

Using getInstancesAsRawEntities doesn't work

#

And public List<T> getInstances() {
return instances;
} doesn't work

#

Because getInstances() return Object and not a list of objects that extends rawentity

#

That's the problem

rare aspen
#

what?

#

no, getInstances returns List<T>

weary sphinx
#

Yes

#

But it should be a list of objects part of a class that extends RawEntity

#

Because

rare aspen
#

it sounds like you're creating a problem out of nothing here to be honest

weary sphinx
#

private List<T> instances = new ArrayList<T>();

rare aspen
#

right, and it is that

weary sphinx
#

Nope

#

Wait

rare aspen
#

T is something that extends RawEntity
List<T> is a list of something that extends RawEntity

weary sphinx
#
public class EntityBatch <T extends RawEntity> {
    private TexturedModel model;
    private List<T> instances = new ArrayList<T>();

weary sphinx
#

Because...

rare aspen
#

it does though?

#

that's just, how generics work

weary sphinx
#
for(EntityBatch batch:batches)
            {
                for(List<RawEntity> instance:batch.getInstancesAsRawEntities())
                {
#

Wait actually

rare aspen
#

you're using a raw type there

#

like i said, provide it with a generic

#

raw types invoke pre-generic behavior

#

use EntityBatch<? extends RawEntity> there

#

then you can use batch.getInstances() as normal

weary sphinx
#

I've done it

#

Already

#

But doesn't work

#

Here

#
public boolean testCollisions(Vec3f newpos, List<EntityBatch<? extends RawEntity>> batches)
rare aspen
#

explain what "doesn't work" means

weary sphinx
#

In the prototype

#

I mean it shows an error

rare aspen
#

you need it here too

#

you're using a raw type there

weary sphinx
#

It shows the error cannot convert element from type object to List<RawEntity>

#

Yes

rare aspen
#

that reverts the entire thing to pre-generic behavior, and your ide probably would have warned you of it

weary sphinx
#

Ohhh

rare aspen
weary sphinx
#
for(EntityBatch<? extends RawEntity> batch:batches)
            {
                for(List<RawEntity> instance:batch.getInstances())
                {
                    if(instance.CheckAABBCollision(instance.getCollisionBox(), newpos, collisionBox))
                    {
                        collisionBox.print("You know are strangers");
                        return true;
                    }
                }
            }

It prints a weird error

#

Type mismatch: cannot convert from element type capture#1-of ? extends RawEntity to List<RawEntity>

rare aspen
#

getInstances() is a List<? extends RawEntity>
you're iterating over it with a foreach
instance is a RawEntity, not a List<RawEntity>

weary sphinx
#

Oh wait that's actually true

#

Damn it worked

#

A huge thanks dude

naive lindenBOT
# weary sphinx A huge thanks dude

If you are finished with your post, please close it.
If you are not, please ignore this message.
Note that you will not be able to send further messages here after this post have been closed but you will be able to create new posts.

weary sphinx
#

I think i'm done now

#

Thanks to you all for helping me

#

@rare aspen

#

@pure sedge

#

@glossy basin

rare aspen
#

you don't have to mention everyone lol

weary sphinx
#

Okay

rare aspen
#

if you want to give credit, it's based on the buttons when you close post, not on mentions

#

differs from other servers a bit here

weary sphinx
#

Okay

#

That's right

#

But thanks again

pure sedge
rare aspen
#

lmao

#

welp kyo chan was right on this ig lmao

Well the fastest is to not do it at all.

weary sphinx
#

What ?

rare aspen
#

the fastest way to get a List<RawEntity> is to not do it because it's unnecessary (in favor of List<? extends RawEntity> for proper subtyping)

weary sphinx
#

Oh wait i have another question

#

Let's say that in the start of the program i do

#

List<EntityBatch<? extends RawEntity>> batches = new ArrayList<EntityBatch<? extends RawEntity>>();

#

Then just after that i do

#

batches.add(<A batch>)

rare aspen
#

(you can use new ArrayList<>() there btw to let java infer the type)

weary sphinx
#

Okay

#

But if then later on i make modifications to it

#

Let's say <the batch>.addEntity(<...>)

#

Will batches.get(0) will hold the modification i've done to the batch

#

And also

#

Just lemmie finish

#

In general

#

Sometimes something weird happens when i program

#

Let's say i do

#

Vec3f player_pos = ...

#

Then i'd do enemy_pos = player_pos

#

Then i do

#

player_pos = <something>

#

And the enemy_pos would actually be <something>

rare aspen
weary sphinx
#

But sometimes it's the case and sometimes it's not

#

It's weird

rare aspen
weary sphinx
#

So it's like in C

#

It passes a reference

#

It doesn't copy at all

rare aspen
weary sphinx
#

If i understand

#

Not python

rare aspen
#

python does this

weary sphinx
#

Nope

#

I'm pretty sure it doesn't

rare aspen
#

actually wait, player_pos = reassigns the variable. unless you're actually mutating it or mutating an object that holds it, that's not the behavior that occurs

rare aspen
weary sphinx
#

Okay

weary sphinx
#

It's weird because sometimes it does it sometimes it doesn't

rare aspen
#

/run

a = { "a": 0 }
b = a
a["a"] = 1
print(b)
grizzled flowerBOT
#

Here is your py(3.10.0) output @rare aspen

{'a': 1}
rare aspen
weary sphinx
#

But it does it only for arrays ?

#

So :

#

Wait

rare aspen
weary sphinx
#
Vector3f player_pos = new Vector3f(0.0f, 0.0f, 0.0f);
Vector3f enemy_pos = player_pos;
player_pos = new Vector3f(1.0f, 2.0f, 4.0f);
rare aspen
#

although, some objects are immutable, so they can't be mutated, so mutations won't propagate because there aren't any mutations to begin with

weary sphinx
#

Okay

rare aspen
#

just to make sure; your Vector3f is immutable right? (it generally should be)

weary sphinx
#

WAit

#

Here is the code

#
public class Vec3f implements Serializable {
    public float x, y, z;
    
    public Vec3f(float x, float y, float z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }
    public Vec3f()
    {
        this.x = 0;
        this.y = 0;
        this.z = 0;
    }
    public Vec3f(Vec3f vector3f)
    {
        this.x = vector3f.x;
        this.y = vector3f.y;
        this.z = vector3f.z;    
    }
}

It's actually Vec3f and not Vector3f

rare aspen
#

so it's mutable

weary sphinx
#

Okay

#

Then how to prevent it ?

rare aspen
#

if you do

Vector3f player_pos = new Vector3f(0.0f, 0.0f, 0.0f);
Vector3f enemy_pos = player_pos;
player_pos.x = 1f;
```this would propagate to `enemy_pos`
#

generally you'd want these to be immutable

weary sphinx
#

Nope because i just want to copy player_pos into enemy_pos

rare aspen
#

3 approaches; make x, y, z final, change Vec3f to a record, or make x, y, z private and implement getters (but not setters)

weary sphinx
fallow turret
weary sphinx
#

Yes

rare aspen
weary sphinx
#

I just want to copy x, y, z of player to enemy

rare aspen
pure sedge
weary sphinx
pure sedge
pure sedge
#

anyways I will let you help rickroll

rare aspen
#

yeah we can discuss this in #general later

pure sedge
#

cause obviously you want to dominate every convo

rare aspen
#

it's not hard when the other person is just wrong...

weary sphinx
rare aspen
#

then you'll have to clone everywhere

weary sphinx
#

Okay i see

#

Thanks then

naive lindenBOT
# weary sphinx Thanks then

If you are finished with your post, please close it.
If you are not, please ignore this message.
Note that you will not be able to send further messages here after this post have been closed but you will be able to create new posts.

weary sphinx
#

But

#

Just to make sure i've understand

#

Let's say that in C i would do :

public ...(int* someIntegerToChange)
{
  *someIntegerToChange = 50
}

What's the equivent of this in java ?

rare aspen
#

there's no equivalent

weary sphinx
#

oh

#

But then java could never be as fast as C or C++

rare aspen
#

in exchange for safety, yes

weary sphinx
#

okay then

weary sphinx
rare aspen
#

people are not perfect

#

it's not plausible for a good programmer to prevent that entirely

#

they could try to, and they could probably make a great attempt

#

but it's not foolproof

#

java isn't foolproof either, but it's been tested and checked a lot more than 1 person's code

#

that's the whole incentive with using safe things that other people have built

weary sphinx
rare aspen
#

yeah

weary sphinx
#

But who know maybe someone one day could find a way to exploit buffer overflows in java*

#

Because java is coded in C

rare aspen
#

yeah

weary sphinx
#

Anyways thanks for all these precious infos !

naive lindenBOT