• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[General] handles

Status
Not open for further replies.
Level 22
Joined
Sep 24, 2005
Messages
4,821
@IcemanBo: I assumed the handles were different, anyway a test map is provided.
JASS:
globals
    location A=Location(0,0)
    location B=Location(0,0)
endglobals

function RunTest takes nothing returns nothing
    local integer a=GetHandleId(A)
    local integer b=GetHandleId(B)
    
    if (a==b) then
        call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10.00,"Same; A("+I2S(a)+") : B("+I2S(b)+") ")
    else
        call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10.00,"Not Same; A("+I2S(a)+") : B("+I2S(b)+") ")
    endif
endfunction


function InitTrig_Test takes nothing returns nothing
    call TimerStart(CreateTimer(),1.0,false,function RunTest)
endfunction

Handle_ID_Test.jpg
 

Attachments

  • Handle Id Test.w3x
    12.3 KB · Views: 27

Chaosy

Tutorial Reviewer
Level 40
Joined
Jun 9, 2011
Messages
13,219
if you do:
JASS:
globals
    location A=Location(0,0)
    location B=A
endglobals

function RunTest takes nothing returns nothing
    local integer a=GetHandleId(A)
    local integer b=GetHandleId(B)
    
    if (a==b) then
        call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10.00,"Same; A("+I2S(a)+") : B("+I2S(b)+") ")
    else
        call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10.00,"Not Same; A("+I2S(a)+") : B("+I2S(b)+") ")
    endif
endfunction


function InitTrig_Test takes nothing returns nothing
    call TimerStart(CreateTimer(),1.0,false,function RunTest)
endfunction

it turns out to be true though.

I got my answer here, thanks both of you. Rep'd
 
Level 22
Joined
Sep 24, 2005
Messages
4,821
@IcemanBo: Oh right! fucked! lol
@Chaosy: No problem, and sorry, my comprehension is really bad atm.
 
Level 14
Joined
Jun 27, 2008
Messages
1,325
Its the same with all handles, even with vjass struct objects. The constructor generates a unique id (handle id for real handles, "this" pointer for struct objects). Its not relevant which parameters you pass to the constructor, so if you call it twice with the same arguments it still creates two independent objects.
If you however copy the variable that stores a handle (or struct object) then you dont create a new object, you just create a new pointer to it. Subsequently the ids are the same.
Another consequence is that if you destroy an object by calling the destructor for a pointer of that object then all pointers to the object will be invalid.

Real handles:
JASS:
local location loc1 = Location(x, y) // Constructor for locations, arguments: x, y
local location loc2 = Location(x, y) // Construct another location
local location locCopy = loc1 // Just another pointer to loc1.

// then:
GetHandleId(loc1) != GetHandleId(loc2)
GetHandleId(loc1) == GetHandleId(locCopy)

// destroy loc1:
call RemoveLocation(loc1)
// --> loc1 invalid
// --> loc2 still valid
// --> locCopy invalid

same with structs:
JASS:
struct MyStruct
endstruct

local MyStruct struc1 = MyStruct.create()
local MyStruct struc2 = MyStruct.create()
local MyStruct strucCopy = struc1


// then:
struc1 != struc2
struc1 == strucCopy
// or the same with explicit cast:
integer(struc1) != integer(struc2)
integer(struc1) == integer(strucCopy)

// destroy struc1:
call struc1.destroy()
// --> struc1 invalid
// --> struc2 still valid
// --> strucCopy invalid

Note that in the last 3 lines the pointers "struc1" and "strucCopy" are still valid integers and can still be used as a functioning object, but as the id is free to be used by the allocator its possible to get conflicts with other objects.
 
Last edited:
Level 15
Joined
Aug 7, 2013
Messages
1,338
I believe there is an exception however. As discussed in this thread, boolexpr objects are actually recycled when they are atomic.

JASS:
boolexpr A = Condition(function main)
boolexpr B = Condition(function main)

if A == B then
  call print("They are the same handle!")
endif
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
"when they are atomic"

care to explain what you mean?

function's filter AND condition will always point to the same address, no matter how many times you call Condition/Filter on the function. Thus they dont leak, because were there all the time

To add to the question:

If you do what you did(set loc2 = loc), they will point to the same handle, the same location, so if you call RemoveLocation(loc2), it will also invalidate the location that is stored in loc. They will also be "equal", because they point to the same object.

This is true for all handle types.(So not true for integers, reals, strings, codes and booleans, because their content is copied when you assign it to another of its type)

The one tricky thing is, what seth mentioned(Theoretically).

JASS:
boolexpr a = Or(function f, null)
boolexpr b = Or(function f, null)

a and b dont point to the same object, but if you have what he wrote, they point to the same object.

However

JASS:
boolexpr a = Filter(function f)
boolexpr b = Filter(function f)

will always point to the same object.
 
Level 15
Joined
Aug 7, 2013
Messages
1,338
"when they are atomic"

care to explain what you mean?

Atomic means the expression can't be broken up into any smaller parts (e.g. when people thought atoms were indivisible). A non-atomic boolexpr in JASS is one that is created by using a logical operator between boolexpr.

Atomic boolexpr aren't boolexpr created by one of the logical operator natives: And, Or, and Not. Those do not get recycled, as you point out in your first example, which is indeed what I was eluding to.

JASS:
boolexpr a = Filter(function f)
boolexpr b = Filter(function f)
will always point to the same object.

That's because filterfunc and boolexpr conditionfunc are the same object I believe.
 
Last edited:
Level 23
Joined
Apr 16, 2012
Messages
4,041
I still dont understand what you mean by atomic in this case. You just made something up, or it seems it like that ot me, anyways. I will say tho that you have a point there tho

filterfunc is not the same as boolexpr.

JASS:
type conditionfunc      extends     boolexpr
type filterfunc         extends     boolexpr

its the same as doing this:

local widget w = CreateUnit(...), you can convert it to parents implicitly
 
Level 15
Joined
Aug 7, 2013
Messages
1,338
It's not made up at all. This explains what an atomic expression is pretty well. I know as well because I've studied (mathematical) logic quite a bit!

a formula that contains no logical connectives or equivalently a formula that has no strict sub formulas.
filterfunc is not the same as boolexpr.

You're right, I meant to say this:

conditionfunc and filterfunc are actually the same.
 
Level 15
Joined
Aug 7, 2013
Messages
1,338
Being atomic isn't gradient / real valued (unless we are doing something statistical based I suppose). There's no metric to evaluate how atomic an expression is unless we created one (e.g. the number of nested logical connectives). An expression is either atomic or it is not (binary valued).

Think about it: if we have a boolexpr created by Or, it has at least two sub boolexpr. Therefore, it's not atomic.

If we have a boolexpr created by Filter or Condition, then it's atomic. You can't break up this boolexpr into any sub parts, hence it's atomic.

Read the article I posted again. Filter just returns a value that can be stored as boolexpr, it's still atomic. For your convenience I've copied the definition again.

a formula that contains no logical connectives or equivalently a formula that has no strict sub formulas.

Or is a binary logical connective, it requires two boolexpr arguments and returns a non-atomic boolexpr. Note that its arguments can be atomic or non-atomic, otherwise we could not nest these logical connective to generate arbitrarily long boolexpr.

Filter or Condition on the other hand aren't logical connectives. They simply perform a type casting: code --> boolexpr. That doesn't change the truth values of the original expression. And these are recycled as well, unlike non-atomic boolexpr as we both have pointed out numerous times.
 
Level 5
Joined
May 6, 2013
Messages
125
The word atomic is a bit like the word god; it changes its (suggested) meaning wherever you go, nobody really knows the details, and apparently, it's just as good as causing warm discussions. I have learned about 5 new meanings of "atomic" in the past 6 months alone.

Anyway, i just dropped by because i couldn't find a tutorial thread explaining the concept of handles and the pesky little details wc3 imposed on them. As often as these questions come up, you'd expect to come across someone linking such a thread, so unless i'm just plain blind, maybe someone could write something like that.
 
Level 15
Joined
Aug 7, 2013
Messages
1,338
In the context of expressions being composed by logical connectives, atomic unambiguously means those expressions which have no sub-parts, which is the context I've been using it in.

Atomic is used in areas of Computer Science that deal with logic: propositional logic, predicate logic / calculus, first order logic, modal logic etc. The classes I took that dealt with these topics were Computer Science courses if that helps.

In any case the generalization holds:

(1) Atomic boolexpr get recycled.

(2) Non-atomic boolexpr do not get recycled.

which contrasts with most other handles.
 
Level 5
Joined
May 6, 2013
Messages
125
In the context of expressions being composed by logical connectives, atomic unambiguously means those expressions which have no sub-parts, which is the context I've been using it in.

which is an arguable definition. Take the "atomic" from predicate logic for example, with S = ({f/0, g/0}, {p/2}), p(f,g), which is short for p(f(),g()), is an atom, though you might argue that it has sub-parts in f() and g(). In the same vein, you could interpret this case as S=({f/0, g/0}, {And/2, Or/2, Filter/1}) with f and g being the functions, and build the expression And(f,g), Or(f,g) and Filter(f), and all of these would be atoms in the context of predicate logic. Then again, this is a formal language we're talking about, and I've never seen a definition of atomic in that context.

Anyways, is there really no "what the heck are handles" thread out there? We really need one Oo
 
Level 15
Joined
Aug 7, 2013
Messages
1,338
which is an arguable definition.

Without context and by itself I agree. But I've described very verbosely several times what meaning of atomic I am using. And it's the perfect way to describe the generalization about how boolexpr handles work: atomic boolexpr get recycled, non-atomic boolexpr do not.

What do you mean they don't get recycled?

Consider these two cases (I'm using the examples from the previous posts)

JASS:
location l1 = Location(0, 0)
location l2 = Location(0, 0)
boolexpr A = Condition(function main)
boolexpr B = Condition(function main)

if l1 != l2 then
  call print("They aren't the same handle!")
endif

if A == B then
  call print("They are the same handle!")
endif

In this sense boolexpr get recycled when they are created without a logical connective, and thus are atomic. When I say recycled, instantiating a new boolexpr variable actually refers to the same boolexpr if it already has been instantiated. Hence why this happens:

JASS:
location l1 = Location(0, 0)
location l2 = Location(0, 0)
boolexpr A = Condition(function main)
boolexpr B = Condition(function main)

call RemoveLocation(l1) //l2 still works
call DestroyBoolexpr(A) //B no longer works!


However, once we use a logical connective, they no longer get recycled, even if they have the same truth values.

JASS:
boolexpr A = Or(Condition(function main), null)
boolexpr B = Or(Condition(function main), null)
//clearly whenever A is true/false, B is likewise true/false
//thus they are equivalent expressions
//but WC3 can't figure this out, so they are both unique instances now

if A == B then
  call print("I'm wrong!")
endif

call DestroyBoolexpr(A) //B will still work!
 
Status
Not open for further replies.
Top