HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Freaking vJass abuse.

07-05-2008, 12:33 AM#1
Vexorian
I have a problem right now, first of all, I wish to move from completely wrong CSCache to "Table" There's a little problem with that and it is that I still need to use H2I , I think H2I increases uglyness of code by 20%, I also think it would look harder for other people, it is actually quite lame.

If you want your map to be sane, it is not good to use more than a gamecache library, gamecache files are very expensive if you ask, specially with that risk associated to them of making things stop working in single player, two independent libraries can't use the same gamecache file, if they figured a way to avoid collissions they would still be unable to deal with the required flushing at init. There's also the small problem that if I let Table as it is right now, the number of scattered H2I functions will mutliply, I personally think I need H2I integrated to Table somehow, because of the scattered H2I risk I just mentioned and the unfriendliness I mentioned in the other paragraph.

I had a dream after all the discussion about the definition of associative arrays with Cohadar. What if I could actually make Tables be associative arrays even for that definition in which keys are not integers!. In fact, even similar to dynamic languages' associative arrays.

Collapse JASS:
//The ideal:
function test takes nothing returns nothing
 local Table t=Table.create()
    set t["oranges"]=12
    set t["apples"]=2
    set t["bananas"]=t["apples"]*2
    set t[34]=t[1923777]+t[-1283]
    set t[ GetTriggerUnit() ] = t[GetTriggerUnit() ] +1

The problem is that the ideal is impossible to make in vJass, I know I control vJass and I could actually make it so function overloading worked , but then it is not something I really want, the second option would be to allow type specialization for functions/methods, this is a nice idea that unfortunately I cannot add without a lot of effort I am not willing to use yet.

So, the closest I got to the ideal was this:
Expand Possible new Table version:

So the code that worked with the "ideal" will look like this:

[/hiddenjass]

Collapse JASS:
//The ugly reality
function test takes nothing returns nothing
 local Table t=Table.create()
    set t.string["oranges"]=12
    set t.string["apples"]=2
    set t.string["bananas"]=t.string["apples"]*2
    set t[34]=t[1923777]+t.integer[-1283] //for consistency I guess
    set t.handle[ GetTriggerUnit() ] = t.handle[GetTriggerUnit() ] +1

So, my conclusions:
  • I love jasshelper's inliner, after all that stuff the contents of test are STILL compiled into native gc usage.
  • If one actually proposes can really abuse vJass and do something that's I (the author) did not expect vJass to be able to do.
  • The compiler is too flexible?

Question, how does the "ugly reality" code look? My excuse would be "Until vJass' compiler gets smarter you need to specify what type to use for the key, (unless it is integer) " But I think the logic is backwards there?

Edit: Thanks to the Jass tag "ugly reality" does not look as shocking as when I look at it in gVim, a screenshot:

Zoom (requires log in)

Edit II: Ah, this is how it compiles:

Collapse JASS:
function test takes nothing returns nothing
 local integer t=s__Table__allocate()
    call StoreInteger(Table__gc , I2S((((t)))) , ("oranges") , ( 12)) // INLINED!!
    call StoreInteger(Table__gc , I2S((((t)))) , ("apples") , ( 2)) // INLINED!!
    call StoreInteger(Table__gc , I2S((((t)))) , ("bananas") , ( (GetStoredInteger(Table__gc , I2S((((t)))) , ("apples"))) * 2)) // INLINED!!
    call StoreInteger(Table__gc , I2S((t)) , I2S((34)) , ( (GetStoredInteger(Table__gc , I2S((t)) , I2S((1923777)))) + (GetStoredInteger(Table__gc , I2S((((t)))) , I2S((- 1283)))))) //for consistency I guess // INLINED!!
    call StoreInteger(Table__gc , I2S((((t)))) , I2S(Table__H2I((GetTriggerUnit()))) , ( (GetStoredInteger(Table__gc , I2S((((t)))) , I2S(Table__H2I((GetTriggerUnit()))))) + 1)) // INLINED!!
endfunction
07-05-2008, 01:07 AM#2
Anitarf
I'm really having trouble understanding how those new method operators are understood by the compiler. What are they normaly used for? This really is some heavy abuse, I'd almost say I'd rather just use H2I myself and get the same functionality while having more understanding of what it is that I'm doing but the point is that it's not the same functionality, since this also allows the use of strings.

I'm looking forward to a more detailed explanation of why it works.

Edit: nevermind, I figured out the logic behind it, it's actually just simple typecasting. Since when do we have type operators (int, string, handle)? Is this something invented specifically to support this abuse or was this feature implemented before and if so for what application? Also, does this not generate any error messages in debug mode? I'd think there should be an error message if you try to do stuff with an uninitialised struct instance.
07-05-2008, 01:59 AM#3
Vexorian
Nah, debug mode does not babysit against using unitialized struct ids. Dunno if it would ever do.

Quote:
Since when do we have type operators (int, string, handle)?
we don't.

Yeah, it is crazy.
07-05-2008, 05:26 AM#4
Feroc1ty
You could make function overloading? Fuck man, PLEASE, I BEG YOU, PLEASE ADD IT TO YOUR LIST OF THINGS TO DO.
07-05-2008, 11:18 AM#5
Anitarf
Quote:
Originally Posted by Vexorian
we don't.

Yeah, it is crazy.
Well, I see you went with a more conventional implementation in the end. It's still possible to do typecasting though, right? We don't actually need to create multiple tables?
Collapse JASS:
globals
    private Table tI
    private HandleTable tH
    private StringTable tS
endglobals

private function init takes nothing returns nothing
    set tI=Table.create()
    set tH=HandleTable(tI)
    set tS=StringTable(tI)
endfunction
There's no conflict this way, unless we get an integer high enough to conflict with handle indexes. But there's a way around that too, if we used something like ""h"+I2S(H2I(key))" instead of "I2S(H2I(key))"?

Edit: I know I can get around this by using structs, but it would still be nice if we had a more direct way of storing strings and reals to GC, other than using the natives directly of course.
07-05-2008, 03:41 PM#6
Vexorian
Collapse JASS:
local Table t=Table.create()
    set HTable(t)[ GetTriggerUnit() ] = 2

It is perfectly possible. (Though it is still evil abuse)

edit:
Quote:
There's no conflict this way, unless we get an integer high enough to conflict with handle indexes. But there's a way around that too, if we used something like ""h"+I2S(H2I(key))" instead of "I2S(H2I(key))"?
There isn't any conflict. (double check the textmacro)
07-05-2008, 03:52 PM#7
cohadar
Collapse JASS:
struct StringTable extends Table
struct UnitTable extends Table
//....
07-05-2008, 04:15 PM#8
Vexorian
Can't replace methods in childs.
07-05-2008, 08:05 PM#9
Anitarf
Quote:
Originally Posted by Vexorian
There isn't any conflict. (double check the textmacro)
I triple checked it and still don't get it... unless "this" is somehow different after typecasting it seems like it would store to the same GC adress.
07-05-2008, 09:05 PM#10
Vexorian
are we talking about the same possible conflict?
07-06-2008, 12:57 AM#11
Anitarf
I mean set tab[i]=x vs set HandleTable(tab)[u]=y in cases when i happens to equal H2I(u).