Syntax for Ordered Struct Literals

Currently ordered, or linked, structs can be created like so:

ordredStruct = StructNew("linked");

We want to choose the best syntax for a shorthand, just like we have array = [] and struct = {}. Below are the proposed options. Please chime in with your preferences or thoughts:

  1. leading type linked:

    linkedStruct = linked:{a:1};

  2. trailing type linked:

    linkedStruct = {a:1,b:2}:linked;

  3. leading type ordered:

    orderedStruct = ordered:{a:1};

  4. trailing type ordered:

    orderedStruct = {a:1,b:2}:ordered;

  5. new built in function:

    orderedStruct = new OrderedStruct({key:value});

  6. new built in function with cfml-like naming convention:

    orderedStruct = new StructOrdered({key:value});

  7. processing directive:

    processingdirective defaultstruct=ā€œorderedā€ {
    orderedStruct = { a:b, c:d }
    }

  8. Application level setting, affects all of the structs initialized with {}:

    Application.cfc {
    this.type.struct.defaultLiteralType=ā€œorderedā€;
    }

  9. A combination of struct literal with array literal:

    orderedStruct = {[ a: 10, b: 20, c: 30 ]};

And you sayā€¦?


Before posting, please read: About the ideas category. The guidelines will more loosely apply here due to the historic nature of this topic and the grouping of ideas in the original thread but please bear them in mind.

Of those mentioned #9 is my favourite as it provides a clear different syntax to allow creation of an ordered structure, but one thatā€™s still familiar.

8 could work and is my second favourite, there may be performance concerns but it would allow people to decide themselves as well as leaving the default behavior unchanged from current.

What is the performance cost to just changing the default literal to be ordered, has anyone benchmarked it? I would be very tempted to turn such an option on, if it were available, just to see how much difference it has on real applications. Possibly also compare it to the cost of trying to achieve the same result without an ordered struct.

Whilst it has been mentioned that such a change could throw people used to the current functionality, as the current functionality is ā€œunorderedā€ then changing it to be ā€œorderedā€ should make no difference other than to simplify for those that expect it to be ā€œorderedā€ already. But if that comes at a performance cost then that becomes a bit unacceptable due to how heavily structs are usually used.

I would be wary of 1-4 because it feels like it would conflict with ternary operators fairly easily, could lead to unexpected issues along the line.

5-6 both feel like the Query.cfc logic, feels overly verbose vs the existing implicit declaration. Same applies in part to 7 in that it adds a lot of extra text just to return the same structure as {} but ordered.

#9 and #6 both would be my vote. Have a literal approach and a concise function approach.

I like the idea of a configurable default, though I think it should apply to all structures and not just literals (e.g. StructNew() also).

Having seen some other discussions around the topic, my preference is for no specific syntax at all as there are possibilities for other variations of StructNew():

StructNew( "linked" );
StructNew( "ordered" ); // same as 'linked'
StructNew( "weak" );
StructNew( "sorted", "textnocase" );
StructNew( "sorted", function( a, b ){ return a.value < b.value; } );

Given the possibilities, Iā€™d like to see a configurable default at the application level that applies to both StructNew() and {} rather than either multiple new syntaxes, or only having a syntax for one of the variations.

{} should be a shorthand for StructNew(), so if there is a default change I agree that it should equally affect both.

I believe that you mixed up the ordered with the sorted that was mentioned elsewhere. ordered maintains the order of insertion of new keys, while sorted might require a comparer function or some indication of how to sort the data.

on that token there would be no room for the shorthand {}, but IMO that shorthand is used much more frequently than the explicit function StructNew()

my preference is #9

Iā€™m not sure how to reply to this and stay within the guidelines because thereā€™s nine suggestions, and I canā€™t just [heart] one of them. And Iā€™m not supposed to +1.

I also have discussion points to raise on most of the options, but canā€™t do that either.

So I need to break one rule to offer support here, and the +1 one rule seems to be the least contentious, so Iā€™ll just offer support for option (9). Thatā€™s really nice.

Will there be a later round during which youā€™ll actually permit discussion on these things?

Cheers.

noted. thank you.

perhaps Iā€™m misreading the ā€œguidelinesā€, but it is my understanding that this is the discussion ā€“ we just ask that all input be productive and add stick to the subject at hand. if you have more comments on this subject then please add them here.

The point of the ā€œrulesā€ is to allow ideas not to be shot down before they have a chance to be grown upon. Of course, in this instance, things like the ā€œheart ruleā€ cannot apply to the original topic due to it bringing in an old conversation into one post so doing as everyone else has here and +1ing the parts you like is, of course, perfectly reasonable. Iā€™ve amended the link accordingly.

Go ahead and raise discussion points. So long as they are driving the conversation forward.

I have also updated the ā€˜rulesā€™ @adam_cameron - made them ā€˜guidelinesā€™, hopefully they will feel less draconian: About the ideas category

#9 makes the most sense to me

  1. A combination of struct literal with array literal:
orderedStruct = {[ a: 10, b: 20, c: 30 ]};

I like #9 for ordered.

How would this syntax handle ā€œsoftā€ and ā€œweakā€. Can you even have a ā€œsoftā€ and ā€œorderedā€ struct for example?

it will not. soft and weak references are not used very commonly. they are used mostly for caching purposes, where the object can be garbage collected without having a severe impact on the application.

not out of the box. you will have to create an ad-hoc data structure, but as mentioned above ā€“ most cases do not require weak or soft references, and in most cases if you need the data ordered, then having the object garbage collected at random can break your application, so itā€™s really not that practical.

Given the broad support for #9. Iā€™ve created a proposal topic for that idea specifically: http://lang.lucee.org/t/struct-literal-syntax-for-ordered-structs-key-value-key2-value2/219. I appreciate that this approach is a little fiddly, but Iā€™m hopeful that it can work well (particularly awkward in this case due to the topic having being discussed at length in the google forum).

More suggestions:

9b) Iā€™ve concerns about readability of mix square and curvy brackets, an alternative:

myStruct = {{ key1:"Value 1", key2:"Value 2" }};
  1. a single character to alter the curvy brackets shorthand:

    myStruct = @{ key1:ā€œValue 1ā€, key2:ā€œValue 2ā€ };

10b) or:

myStruct = { key1:"Value 1", key2:"Value 2" }$;
  1. Or even we can alter the operator itself, maybe here we should think how to extend this to other types (array, assignation, closure, etc.)

    myStruct @= { key1:ā€œValue 1ā€, key2:ā€œValue 2ā€ };

1 Like

What about simply myLinkedHash=[a:b,c:d] - as in allowing named elements into an array - which is already in a fixed order by default
Nearly all the functions/methods associated with both arrays and structures would then apply.
To start it out empty myLinkedHash=[:];.
Appending can be as myLinkedHash.e=f;, myLinkedHash.append([e:f]) or myLinkedHash[]=(e:f);
Inserting can be myLinkedHash.insertAt(3,'e',f) or perhaps a shorthand myLinkedHash[-3]=(e:f);

In the end ACF decided for us on this:

ACF example

<cfscript>
departments = structNew("Ordered");
 /** On iterating this struct, you get the values in insertion order, which is the way you inserted the values. **/
 
 /** Create a structure and set its contents. **/
      
     departments.John = "Sales";
     departments.Tom = "Finance";
     departments.Mike = "Education";
     departments.Andrew = "Marketing";
      
 /** Build a table to display the contents **/
      
</cfscript>

IMO ā€œlinkedā€ should simply be the default type - and the struct sould be sortable.

please have in mind that linked structs are slower and need a little bit more memory, that is the reason it is not.

lol ā€¦ they went with my idea