Skip to main content

News

Topic: Link.js v0.4.2 (Read 97616 times) previous topic - next topic

0 Members and 3 Guests are viewing this topic.
  • Radnen
  • [*][*][*][*][*]
  • Senior Staff
  • Wise Warrior
Re: Link.js v0.2.10
Reply #135
Bruce, FatCerberus, LordEnglish, PowerCommand, whatever you are: Link 0.2.10 might now fix your Sphere 1.5 issues. If not, it helps in SSFML anyways. :)
If you use code to help you code you can use less code to code. Also, I have approximate knowledge of many things.

Sphere-sfml here
Sphere Studio editor here

  • Fat Cerberus
  • [*][*][*][*][*]
  • Global Moderator
  • Sphere Developer
Re: Link.js v0.2.10
Reply #136
Haven't seen any segfaults since upgrading to 0.2.10, so I guess that was it.  What was the exact issue, anyway?  You said it was a severe bug, so I was curious why it was so severe.

Oh, new idea for aliases: 'include' and 'exclude' for filter and reject, respectively.
neoSphere 5.9.2 - neoSphere engine - Cell compiler - SSj debugger
forum thread | on GitHub

  • Radnen
  • [*][*][*][*][*]
  • Senior Staff
  • Wise Warrior
Re: Link.js v0.2.11
Reply #137
It was severe 'cause it exploited perhaps a bug of spidermonkey.

The line of code I fixed went like this
Code: (javascript) [Select]

// from:
var args = [].splice.call(arguments, 0, arguments.length);

// to:
var args = [].slice.call(arguments, 0);


That was shorthand for remove nothing, append the current length. Which was weird. The arguments then get passed on and would work without issue... until you run out of memory. I don't know how but by doing the above the arguments grow out of proportion and I guess that memory isn't handled right in SM 1.5, hence the immediate crash after a while of use. Slice makes sure to do a proper cast to an array, adding nothing extraneous to the array. It was a weird mistake on my end, because I'm stupid and didn't know what splice did, even though it seemed to work in testing.

include and exclude... hmmm... ok. Aliases are cheap to make in Link. :) I might make an alias factory for link... that solves all alias problems if I offload them to the end user:

Code: (javascript) [Select]

Link.alias('filter', 'include').alias('reject', 'exclude');


I think it's for the best. I've noticed through my research of many of these kinds of libraries that they all use slightly different naming conventions and conventions seem to change over time.

Edit:
I updated Link to 0.2.11 which see the newly added alias method.
  • Last Edit: March 27, 2014, 02:27:03 am by Radnen
If you use code to help you code you can use less code to code. Also, I have approximate knowledge of many things.

Sphere-sfml here
Sphere Studio editor here

  • Fat Cerberus
  • [*][*][*][*][*]
  • Global Moderator
  • Sphere Developer
Re: Link.js v0.2.11
Reply #138
Yay, now I can make my own aliases!  Actually I probably won't use it, but I can see other people finding a use for it.

I'm finding Link to be invaluable for Spectacles development.  I've been using it a lot in the implementation of my complex statuses with all their special conditional clauses. :-)
neoSphere 5.9.2 - neoSphere engine - Cell compiler - SSj debugger
forum thread | on GitHub

  • Fat Cerberus
  • [*][*][*][*][*]
  • Global Moderator
  • Sphere Developer
Re: Link.js v0.2.11
Reply #139
New feature idea, assuming this can't already be done somehow: Some sort of feature where you can query for multiple different items at once.  For example, I have a tagging feature for statuses where they can be tagged with such things as "ailment", "debuff", etc.  There doesn't seem to be a simple way to run a query that checks for multiple tags at once.  Here's an example of something I'm currently doing with Link:

Code: (javascript) [Select]
BattleUnit.prototype.liftStatusTag = function(tag)
{
var statusIDs = Link(this.statuses)
.where(function(status) { return Link(status.statusDef.tags).contains(tag); })
.pluck('statusID')
.toArray();
for (var i = 0; i < statusIDs.length; ++i) {
this.liftStatus(statusIDs[i]);
}
};


For reference, a status definition in Specs looks like this:
Code: (javascript) [Select]
disarray: {
  name: "Disarray",
  tags: [ 'acute' ],
  initialize: function(unit) {
    this.actionsTaken = 0;
  },
  acting: function(unit, eventData) {
    if (eventData.action.rank != Infinity) {
      eventData.action.rank = Math.floor(Math.min(Math.random() * 5 + 1, 5));
    }
    ++this.actionsTaken;
    if (this.actionsTaken >= 3) {
      unit.liftStatus('disarray');
    }
  }
},


Basically what I want to be able to do is query a unit's list of active statuses, and then filter the result based on whether any status's tags array contains any tags listed in ANOTHER array (example: querying for both debuffs and ailments), and then operating on the result (to continue the example, lifting those statuses returned by the query).

I guess essentially what I'm asking for is a vector version of .filterBy(), now that I think about it.  filterBy takes the name of a scalar member and passes any item for which that member's value matches one specified, whereas this would take the name of an array member and pass any item for which that array contained any value in a specified array.  e.g.:
Code: (javascript) [Select]
Link(statuses).vectorFilterBy('tags', [ 'ailment', 'debuff' ]).each(function(item) {
    // ...
}


Maybe even have a hybrid scalar/vector version as well, that checks whether a scalar member matches any of a list of values.
neoSphere 5.9.2 - neoSphere engine - Cell compiler - SSj debugger
forum thread | on GitHub

  • Radnen
  • [*][*][*][*][*]
  • Senior Staff
  • Wise Warrior
Re: Link.js v0.2.11
Reply #140
I see you want to check against a list of items in an or-like fashion. Currently or-like behavior is not present in a few of the operations. The chains are and-like where if they fail the query is terminated.

I see. I'll look into this and add the functionality.

Edit: ok, I made an ultra fast version of filterBy, but it seems that it's fast because I rely on the array.indexOf feature which is not available in SM 1.5. Otherwise it's fairly slow (I'd be nesting a Link.contains in the filter, which makes it much slower than the array.indexOf method).
  • Last Edit: April 15, 2014, 10:48:16 pm by Radnen
If you use code to help you code you can use less code to code. Also, I have approximate knowledge of many things.

Sphere-sfml here
Sphere Studio editor here

  • Fat Cerberus
  • [*][*][*][*][*]
  • Global Moderator
  • Sphere Developer
Re: Link.js v0.2.11
Reply #141
Is it still just as slow if you use a polyfill for indexOf()?
neoSphere 5.9.2 - neoSphere engine - Cell compiler - SSj debugger
forum thread | on GitHub

  • Radnen
  • [*][*][*][*][*]
  • Senior Staff
  • Wise Warrior
Re: Link.js v0.2.11
Reply #142
It's twice as slow with a polyfill and I suspect in Sphere it'd be even slower. It was fast because the array's indexOf function is a native method and so gets all the benefits of a purely compiled language like C.

But, with a simple hand-written indexOf it seems to do well, really well! So I'll just do this. I'll update the code in a bit.

Here is the api (so it's non-breaking):
Link(array).filterBy('name', itemA, itemB, ...);

But, this is faster than filterBy by 7 times:
Code: (javascript) [Select]

Link(array).filter(function(item) {
   return item.name == itemA || item.name == itemB;
});


So, if you truly want speed a custom filter is always better. I still want to add in the filterBy because at least it's still more modular than having to write different filters for each test.

I'm changing the api again. It's now like this:
Link(array).filterBy("name", A);  // a single entity
Link(array).filterBy("name", [A, B, C, ...]); // an array of items

In this way it's obvious the algorithm is optimized in the case when you are filtering by a single item. This alone is still much faster than a pluck-then-filter. I wanted to also go with an array so it can be modified elsewhere before introducing it to the function call. I realized a multiple-arguments approach reduces the way in which you can put in inputs to the function.
  • Last Edit: April 17, 2014, 12:04:18 am by Radnen
If you use code to help you code you can use less code to code. Also, I have approximate knowledge of many things.

Sphere-sfml here
Sphere Studio editor here

  • Fat Cerberus
  • [*][*][*][*][*]
  • Global Moderator
  • Sphere Developer
Re: Link.js v0.2.11
Reply #143
That's a good start, although it doesn't fully solve my tags problem.  My statuses are defined with an array of tags, what I want is to be able to query a unit's list of statuses and return the ones whose taglist contains any of the specified values.  Basically an or-like filter in 2 dimensions, or if you will, vector filterBy().  I do realize this is potentially very slow (if I'm figuring this right it's roughly O(n^3) (cubic) complexity in the worst case), but I wouldn't be doing it ridiculously often either.  Maybe once on a battler's turn, to heal a bunch of similar statuses at once, for example.

I can't even do .expandInto('tags') since that remaps the whole query.  Honestly I'm not even sure I could implement this with a custom filter(), although maybe I'm just not using my imagination enough...
  • Last Edit: April 17, 2014, 01:07:14 am by Lord English
neoSphere 5.9.2 - neoSphere engine - Cell compiler - SSj debugger
forum thread | on GitHub

  • Radnen
  • [*][*][*][*][*]
  • Senior Staff
  • Wise Warrior
Re: Link.js v0.2.11
Reply #144
What about this? All functions contain two parameters, the filtered result and the original 'parent'. Like this:

Code: (javascript) [Select]

Link(array).pluck("prop").each(function(item, parent) { /* ... */ });

// example of printing hello world 3 times from use of pluck:
var item = { greet: "hello", object: "world" };
Link([item, item, item]).pluck("greet").each(function(item, parent) { print(item + " " + parent.object); });


Although the query continues, the second param has the original host object. I don't know how this'll affect speed though...
  • Last Edit: April 17, 2014, 01:43:40 am by Radnen
If you use code to help you code you can use less code to code. Also, I have approximate knowledge of many things.

Sphere-sfml here
Sphere Studio editor here

  • Fat Cerberus
  • [*][*][*][*][*]
  • Global Moderator
  • Sphere Developer
Re: Link.js v0.2.11
Reply #145
That's a nice idea, I'm not sure how this solves my tag-search issue though.

You understand what I'm trying to accomplish, right?
neoSphere 5.9.2 - neoSphere engine - Cell compiler - SSj debugger
forum thread | on GitHub

  • Radnen
  • [*][*][*][*][*]
  • Senior Staff
  • Wise Warrior
Re: Link.js v0.2.11
Reply #146

You understand what I'm trying to accomplish, right?


Oooh, I see now. Tags is the array and you are wanting to check many items against one without resorting to another Link context. You basically want a contains that conditionally continues the chain rather than stops it.

Code: (javascript) [Select]

BattleUnit.prototype.liftStatusTag = function(tag)
{
        var me = this; // to prevent use of a .bind();
        var statusIDs = Link(this.statuses)
                .pluck('statusDef') /* problem area here, we lose the original status array */
                .hasIn('tags', tag) /* or whatever */
                .each(function(statusDef, status) { me.liftStatus(status.statusID) }); /* second param supplied by pluck */
};


I think that may do what you want per your example. But I don't have a hasIn() method implemented yet, so I'll go do that. Also this would make use of the second parameter containing the parent object belonging to the property of that initial pluck since pluck can whittle down the size of the data being processed.

This would take a lot of existing reworking and I'm not sure what the payoff is (the pluck adding parent part). Is this closer to what you want?

Edit: Option 2 doesn't solve the problem by reducing total number of link contexts, but I think it's a bit more elegant. I don't think this is a bad idea at all, in fact the use of multiple link contexts can help with readability and what you are trying to do in an inner-loop. The operation here is around O(m*n) in complexity, where m is number of statuses and n is number of tags.
Code: (javascript) [Select]

BattleUnit.prototype.liftStatusTag = function(tag)
{
        var me = this; // to prevent use of a .bind();
        Link(this.statuses).each(function(status) {
                if (Link(status.statusDef.tags).contains(tag)) me.liftStatus(status.statusID);
        });
};
  • Last Edit: April 17, 2014, 03:41:34 am by Radnen
If you use code to help you code you can use less code to code. Also, I have approximate knowledge of many things.

Sphere-sfml here
Sphere Studio editor here

  • Fat Cerberus
  • [*][*][*][*][*]
  • Global Moderator
  • Sphere Developer
Re: Link.js v0.2.11
Reply #147
Okay, we're getting closer, but what I actually want is this:

Code: (javascript) [Select]
BattleUnit.prototype.liftStatusTags = function(tags)
{
    var me = this; // to prevent use of a .bind();
    Link(this.statuses).each(function(status) {
        if (Link(status.statusDef.tags).containsAny(tags)) me.liftStatus(status.statusID);
    });
};


...except ideally there should also be a filter equivalent of containsAny as well.  "OR-like filter in 2 dimensions" is the best description I can give for it.  Which, yes, I realize, is O(m*n*l) complexity.
neoSphere 5.9.2 - neoSphere engine - Cell compiler - SSj debugger
forum thread | on GitHub

  • Radnen
  • [*][*][*][*][*]
  • Senior Staff
  • Wise Warrior
Re: Link.js v0.2.11
Reply #148
Many to many filtering. I see. I can do this for contains, but not for filter, or otherwise unroll becomes a weird thing. Like why unroll when you can do a 2D filter? Hmm... But then again it's all about keeping the original context.

I still don't know how a 2D filter can help you there, namely because of checking inside of statusDef. The only sensible way I can think of is schema-based filtering, like so:

Code: (javascript) [Select]

Link(this.statuses).orFilter({ statusDef: "tags" }, [tagA, tagB, ...]).each(function(status) { me.liftStatus(status.statusID); });

// alternatively:
Link(this.statuses).orFilter("statusDef.tags", [tagA, tagB, ...]).each(function(status) { me.liftStatus(status.statusID); });


But I'm sure the speed will take a small hit each time to parse the filter condition. This might just be it, then.
If you use code to help you code you can use less code to code. Also, I have approximate knowledge of many things.

Sphere-sfml here
Sphere Studio editor here

  • Fat Cerberus
  • [*][*][*][*][*]
  • Global Moderator
  • Sphere Developer
Re: Link.js v0.2.11
Reply #149
If all you can do is containsAny, then that's fine-- it would serve my needs.  I can definitely understand not wanting to do the 2D filter as it would be a major performance hit if abused.  The hit is forgivable with a one-time check like contains, not so much in a general-purpose filtering operation. :)
neoSphere 5.9.2 - neoSphere engine - Cell compiler - SSj debugger
forum thread | on GitHub