Revisit StructNew( "linked" | "weak" ), etc.?

Yes, absolutely. Micha has already created a StructNew( 'ordered' ) alias indeed: https://github.com/lucee/Lucee/commit/7404a0b8602d60ec9213823ca212f4c40e8954d4.

That said, looking at the code there appear to be a number of hidden aliases:

public static int toType(String type) throws ApplicationException {
    type=type.toLowerCase();
    if(type.equals("linked")) return Struct.TYPE_LINKED;
    else if(type.equals("ordered")) return Struct.TYPE_LINKED;
    else if(type.equals("weaked")) return Struct.TYPE_WEAKED;
    else if(type.equals("weak")) return Struct.TYPE_WEAKED;
    else if(type.equals("syncronized")) return Struct.TYPE_SYNC;
    else if(type.equals("synchronized")) return Struct.TYPE_SYNC;
    else if(type.equals("sync")) return Struct.TYPE_SYNC;
    else if(type.equals("soft")) return Struct.TYPE_SOFT;
    else if(type.equals("normal")) return Struct.TYPE_REGULAR;
    else if(type.equals("regular")) return Struct.TYPE_REGULAR;
    else throw new ApplicationException("valid struct types are [normal, weak, linked, soft, synchronized]");
}

Do people feel that StructNew( 'weak' ) and StructNew( 'soft' ) could also benefit from clearer aliases? I’m not sure, but thought I’d put it out there.

(either way - the aliases above should be documented)

I think - unfortunately - the implementation itself needs a rethink. “weak” and “soft” are not types of structs (or, indeed types of data structures of any sort), they refer to the volatility of the reference to the data structure.

There are potentially different sorts of struct: default, ordered, sorted, etc. Those make sense to implement using the structNew() (maybe with a constant for the variation, not a string though? Different thread, I guess) variations you mention.

However one could have a weak ordered struct, or a soft array, or [whatever]. Those two are closer to access modifiers than they are to types (that is not to say they are equivalent to access modifiers; they’re just closer to those than types).

One might have this:

myWeaklyReferencedOrderedStruct = (weak) (ordered) {first="one", second="two"};

A better and more CFML-ish sort of syntax would just be to go the OO route perhaps:

myWeaklyReferencedOrderedStruct = new WeakReference({[first="one", second="two"]});
// or
myWeaklyReferencedOrderedStruct = new WeakReference(new OrderedStruct());
myWeaklyReferencedOrderedStruct.first = "one";
myWeaklyReferencedOrderedStruct.second = "two";

I realise this is not an answer to your question, but it’s perhaps something to think about in conjunction.

To comment more directly only your question: I think you should pick one alias for each construct to persist with, and document the rest, but mark them all as “deprecated” (or “not recommended”, whatever). It benefits no-one having these different variations around, IMO.


Adam

2 Likes

I don’t. the ony practical use case I found for these types is for caches, and IMO if you create a cache it shouldn’t be done in CFML.

if we were to add a whole new type for caching objects, implemented in Java, then I’d be for it. for example instantiated like so:

myCache = CacheNew(1024, "MRU");  // creates a cache with size of 1,024 and most-recently-used eviction policy
3 Likes

I’d be more inclined to only document the ones that we want people to use (or are compelled to support for CFML compatibility) and deprecate all the others.

By the sounds of things it might be an idea to deprecate weak and soft while we are at it.

2 Likes

many of the options in the source code are aliases, mostly due to typos/misspelling at first, and then correction, e.g. syncronized vs synchronized, so sure, only the ones that we want people to use should be documented.

I wouldn’t deprecate these two unless we add a Cache Type as I suggested above. even though it’s not ideal to implement in CFML, it is convenient and easy to so at times.

Well what is the act of “deprecating” if not documenting it? Either way, there needs to be a page someone can land on from a Google search when they ask themselves “WTF is this thing I am looking at in this code I have inherited?”. Even if that is SEOed sufficiently that it points to the same page as the “supported” syntax, then that’s an undertaking to be… um… under…erm…took. Undertooken. [cough].

Bottom line: whatever is currently in Lucee’s CFML needs to be documented. What shape that documentation takes, and the message it delivers is something else.

Let’s not conflate these two things. They’re not the same.

There must’ve been a reason that they were added to the language in the first place. Perhaps the planning that went into that can be shared, so we can see what the basis for the work was. I presume there was a good reason for it. But either way: this thread is not the correct context for that discussion.

We are talking about something that has been dug out of the Lucee core code. This is not something that has been publicised in anyway. Lets agree not to “deprecate” nor to “document” things which are unknown, and unwanted.

There’s little point spending our precious time documenting the unknown to let people know that which they didn’t know is now not to be known :scream:

1 Like

Oh, I don’t know… :wink:

Nah, fair cop. I didn’t look too closely at the aliases Dom plucked out of the source code, and they all look a bit pointless to me: allowing for spelling variations (some of which are spelling mistakes, as Igal points out) and the like. They probably should never have been in there in the first place.

That said: in the time we’ve spent discussing it, any one of us could have edited the relevant docs page, listed the aliases, and said “don’t use these: they’re there for internal reasons and not intended for public consumption”. That’s about the level of documentation I was talking about.

I didn’t want to do this myself as I didn’t want to make the decision as to the future of these things. If we’re agreed though, I’m happy to make that update, then we can move on and disagree about something else instead.

as a side note, the is not possible as replacement

myWeaklyReferencedOrderedStruct = new WeakReference({[first="one", second="two"]});

in that case the reference to the struct would be “weak”, but with

myWeaklyReferencedOrderedStruct = structNew("weak");

the keys/values inside the struct are weak.

i personally use structNew(“soft”|“weak”) a lot inside cfml and java, because it is a very simple way to cache stuff and also a different way to the cache functions.
this way to “cache” is memory sensitive and not time sensitive like the cache functions are.
the garbage collector clean u.
In my opion this is a very strong feature in Lucee that needs more public awarness and should not be deprecated.

1 Like

But is that what I want? Surely when created a weak reference, it should only apply to the very reference I… um… refer to. It should not second-guess what kind of references to make to other objects it internally references, should it?

If I want those other references to be weak, then I’d make them weak.

Also I wonder what the gain is in making the internal references weak? I’ve only done superficial reading - and have never used these things - but from my “understanding” as soon as the outer one is GCed, then the others would be as well anyhow, as they would have no further references to them anyhow. So it seems like work for the sake of it?

Am I missing something (entirely likely)?

I think that you are missing something.

Memory management in Java is done for you automatically behind the scenes, courtesy of the Garbage Collector (GC). The GC reclaims previously used memory by removing “dead” objects.

Objects are considered “dead” if there are no references to them from the root of the JVM. The problem arises when you cache objects, so let’s say you create a cache with the results of a long process so that you don’t need to run the lengthy process each time:

var cachedObject = runLongProcess(key);
Application.data.cache[key] = value;

Now as long the Application.data.cache object is “alive”, the value stays in memory and will never be reclaimed, which is fine if you know for a fact that the cache store will never get crazy-large.

But if you keep adding objects to the cache store without any limitation – it is only a matter of time before you hit an OutOfMemoryException – because even objects that have been dead for days or weeks will still have a reference to them from the cache store.

Setting the reference type to “weak” or “soft” simply tells the GC to not consider that reference when determining whether an object is “alive” or not, so if there are other references to the object, it will stay in memory, but if all other references are long gone and the only reference is from the Hashtable (Struct) then it will be considered “dead” and safe to remove.

Possibly, but what you then go on to 'splain kinda ignores what Micha & I were talking about.

I understand the concept. I was drawing attention to a specific case Micha referenced.

What is a Synchronized struct?

thread safe, in Lucee al struct and scopes are thread safe by default (changed in Railo 4.2), so this type is obsolete and only exists for backward compatibility