Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Object's property is not found when invoking function for 1st time, it is found on 2nd time #48088

Closed
felipeek opened this issue Jan 2, 2023 · 7 comments

Comments

@felipeek
Copy link

felipeek commented Jan 2, 2023

Hello, I am facing an weird issue. The property of an object (:normals) is not being found, even though it is there.

It seems that the issue is happening because I am invoking the code from within a function. If the code is executed outside the function, then it works as expected. Also, if I execute the function a second time using the same kernel, then it finds the property!

The behavior seems somewhat random, but it is very easy to reproduce.

Minimal working example:

using Pkg
Pkg.activate(joinpath("tmpDeps"))
Pkg.instantiate()

Pkg.add(PackageSpec(name="FileIO", version="1.16.0"))
Pkg.add(PackageSpec(name="MeshIO", version="0.4.10"))

using FileIO

function GraphicsMeshCreateFromObj()
	objPath="<path-to-cube.obj>"

	# Load a model mesh
	rawMesh = FileIO.load(objPath)

	println(hasproperty(rawMesh, :normals))
	
	rawMesh
end

A = GraphicsMeshCreateFromObj() # Prints false
B = GraphicsMeshCreateFromObj() # Prints true (?)

println(A == B) # they are the same!

Needs the cube.obj file:

# cube.obj
#
 
g cube
 
v  0.0  0.0  0.0
v  0.0  0.0  1.0
v  0.0  1.0  0.0
v  0.0  1.0  1.0
v  1.0  0.0  0.0
v  1.0  0.0  1.0
v  1.0  1.0  0.0
v  1.0  1.0  1.0

vn  0.0  0.0  1.0
vn  0.0  0.0 -1.0
vn  0.0  1.0  0.0
vn  0.0 -1.0  0.0
vn  1.0  0.0  0.0
vn -1.0  0.0  0.0
 
f  1//2  7//2  5//2
f  1//2  3//2  7//2 
f  1//6  4//6  3//6 
f  1//6  2//6  4//6 
f  3//3  8//3  7//3 
f  3//3  4//3  8//3 
f  5//5  7//5  8//5 
f  5//5  8//5  6//5 
f  1//4  5//4  6//4 
f  1//4  6//4  2//4 
f  2//1  6//1  8//1 
f  2//1  8//1  4//1 

Additional info:

Output of versioninfo():

versioninfo()
Julia Version 1.8.4
Commit 00177ebc4fc (2022-12-23 21:32 UTC)
Platform Info:
  OS: Linux (x86_64-linux-gnu)
  CPU: 8 × Intel(R) Core(TM) i7-8705G CPU @ 3.10GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-13.0.1 (ORCJIT, skylake)
  Threads: 1 on 8 virtual cores

Installed julia by downloading x64 binaries for Linux (glibc)

@felipeek felipeek changed the title Object's property is not found when invoking function for 1st time, finds on 2nd time Object's property is not found when invoking function for 1st time, it is found on 2nd time Jan 2, 2023
@sefffal
Copy link

sefffal commented Jan 2, 2023

I would guess this might be an issue with MeshIO and not base Julia.
Instead of checking whether it has a property, it might be more fruitful to display the return value type.

@felipeek
Copy link
Author

felipeek commented Jan 2, 2023

@sefffal It might be an issue with MeshIO. However, the behavior that I am seeing is very weird - it really seems something is off with the language.

it might be more fruitful to display the return value type.

The return type is the same in both cases (via println(typeof(rawMesh))):

GeometryBasics.Mesh{3, Float32, GeometryBasics.TriangleP{3, Float32, GeometryBasics.PointMeta{3, Float32, GeometryBasics.Point{3, Float32}, (:normals,), Tuple{GeometryBasics.Vec{3, Float32}}}}, GeometryBasics.FaceView{GeometryBasics.TriangleP{3, Float32, GeometryBasics.PointMeta{3, Float32, GeometryBasics.Point{3, Float32}, (:normals,), Tuple{GeometryBasics.Vec{3, Float32}}}}, GeometryBasics.PointMeta{3, Float32, GeometryBasics.Point{3, Float32}, (:normals,), Tuple{GeometryBasics.Vec{3, Float32}}}, GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}, StructArrays.StructVector{GeometryBasics.PointMeta{3, Float32, GeometryBasics.Point{3, Float32}, (:normals,), Tuple{GeometryBasics.Vec{3, Float32}}}, NamedTuple{(:position, :normals), Tuple{Vector{GeometryBasics.Point{3, Float32}}, Vector{GeometryBasics.Vec{3, Float32}}}}, Int64}, Vector{GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}}}}

The return type looks correct (and, in both cases, :normals is there).

There is also another very weird thing: If I run this same code, but within a function, then the issue always happens. Example:

using Pkg
Pkg.activate(joinpath("tmpDeps"))
Pkg.instantiate()

Pkg.add(PackageSpec(name="FileIO", version="1.16.0"))
Pkg.add(PackageSpec(name="MeshIO", version="0.4.10"))

using FileIO

function GraphicsMeshCreateFromObj()
	objPath="/home/felipeek/Desktop/cube.obj"

	# Load a model mesh
	rawMesh = FileIO.load(objPath)

	println(hasproperty(rawMesh, :normals))
	
	rawMesh
end

function Test()
	A = GraphicsMeshCreateFromObj() # Prints false
	B = GraphicsMeshCreateFromObj() # Prints true (?)
end

Test()

Now suddenly hasproperty returns false in both cases. So the behavior changes just by executing the code within the function.

@vtjnash
Copy link
Sponsor Member

vtjnash commented Jan 2, 2023

#265

@sefffal
Copy link

sefffal commented Jan 3, 2023

A quick glance at the MeshIO code seems to show attributes of the Mesh object are determined at runtime based on a variety of conditions, including normals:
https://github.com/JuliaIO/MeshIO.jl/blob/1218fd27289d3c1c7b3c822d1661a34e6da6f9f8/src/io/obj.jl#L122

@felipeek
Copy link
Author

felipeek commented Jan 3, 2023

Yes, attributes are determined at runtime, hence why I was performing this check in the first place. In my example, however, I am always loading the same mesh, which has normals. Therefore, the normals should always be there (and they are always there if I don't run the code from within a function).

It could be a bug in MeshIO? I suppose so, but the fact that the behavior changes if I run the exact same code from within a function or not, or by running a second time, is what made me believe this was not solely related to MeshIO.

@felipeek
Copy link
Author

felipeek commented Jan 3, 2023

I found a fix. It turns out that code was lacking using MeshIO. I still don't understand exactly what was happening, since MeshIO code was clearly being executed. However, I think this is probably outside of the scope of the base lang, so I will close the ticket.

Thanks for the responses!

@felipeek felipeek closed this as completed Jan 3, 2023
@sefffal
Copy link

sefffal commented Jan 3, 2023

As noted by vjtnash method definitions can change between top-level invocations but not within a function call (unless invokelatest is used).
I’m not sure the source of the bug in MeshIO’s integration with FileIO, but that’s why you saw it behave differently within and without the function.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants