Lucee vs legacy CFML

This is a continuation from the tread Outsider perspective
https://groups.google.com/forum/?hl=en#!topic/lucee/5Ol7vTOm6Gk[101-125-false] which
was getting long and fragmented.

Here are some suggestions off-the-cuff from Micha (see the other tread for
context).

So what should a .lucee do better in all this cases.

  • ditch cfoutput-query, it is useless
  • lucee is already passing arrays by ref, so no need to change here
  • ditch cfm based custom tags, we have support for component based custom
    tags
  • ditch “var” ( I know people love var, I do it as well, but it makes now
    sense, the “local” scope is the one following the logic of the language)
  • ditch all the bullshit the local scope does for backward compatibility.
  • if we already on this topic, ditch the argument scope, we only need one
    local scope for functions.
  • ditch the variables scope in components and make the this scope private
    by default.
  • ditch application.cfm of course.
  • ditch dot notation upper case
  • scope cascading to strict
  • … And lot more
  • Then the conversion centered around local vs var in cffunction? I am
    not attached to var or Local but I like fast and I like being able to put
    thing into the variables scope inside the CFComponent. What makes sense
    from a technical perspective? I also like the idea of doing away with the
    argument scope. There would just be a local scope or a function scope.

  • I think most people want to see looping cfoutput go away. For me I
    have never used cfoutput group unless it was forced on me by the creator of
    the original code.

  • Application.cfm & OnRequestEnd.cfm should be removed -
    Application.cfc makes more sense.

Andrew Penhorwood

To be honest we did already a lot of talking behind the scene a while back
about exact this topic, the idea of the .lucee extension is new but doing a
clean version not. We had a group of people participating in the process to
define what means “clean”.
The result of this talks was a detailed list, I will publish that list asap.
So you get a lot more details…

MichaAm Sonntag, 8. Februar 2015 schrieb Andrew Penhorwood :

This is a continuation from the tread Outsider perspective
https://groups.google.com/forum/?hl=en#!topic/lucee/5Ol7vTOm6Gk[101-125-false] which
was getting long and fragmented.

Here are some suggestions off-the-cuff from Micha (see the other tread for
context).

So what should a .lucee do better in all this cases.

  • ditch cfoutput-query, it is useless
  • lucee is already passing arrays by ref, so no need to change here
  • ditch cfm based custom tags, we have support for component based
    custom tags
  • ditch “var” ( I know people love var, I do it as well, but it makes now
    sense, the “local” scope is the one following the logic of the language)
  • ditch all the bullshit the local scope does for backward compatibility.
  • if we already on this topic, ditch the argument scope, we only need one
    local scope for functions.
  • ditch the variables scope in components and make the this scope
    private by default.
  • ditch application.cfm of course.
  • ditch dot notation upper case
  • scope cascading to strict
  • … And lot more
  • Then the conversion centered around local vs var in cffunction? I
    am not attached to var or Local but I like fast and I like being able to
    put thing into the variables scope inside the CFComponent. What makes
    sense from a technical perspective? I also like the idea of doing away
    with the argument scope. There would just be a local scope or a function
    scope.

  • I think most people want to see looping cfoutput go away. For me I
    have never used cfoutput group unless it was forced on me by the creator of
    the original code.

  • Application.cfm & OnRequestEnd.cfm should be removed -
    Application.cfc makes more sense.

Andrew Penhorwood


You received this message because you are subscribed to the Google Groups
“Lucee” group.
To unsubscribe from this group and stop receiving emails from it, send an
email to lucee+unsubscribe@googlegroups.com.
To post to this group, send email to lucee@googlegroups.com.
To view this discussion on the web visit
https://groups.google.com/d/msgid/lucee/cd5a1157-ab2b-4c3e-8eb2-1ff169db4ff8%40googlegroups.com
https://groups.google.com/d/msgid/lucee/cd5a1157-ab2b-4c3e-8eb2-1ff169db4ff8%40googlegroups.com?utm_medium=email&utm_source=footer
.
For more options, visit https://groups.google.com/d/optout.

This is a continuation from the tread Outsider perspective
https://groups.google.com/forum/?hl=en#!topic/lucee/5Ol7vTOm6Gk[101-125-false] which
was getting long and fragmented.

Here are some suggestions off-the-cuff from Micha (see the other tread for
context).

So what should a .lucee do better in all this cases.

  • ditch cfoutput-query, it is useless

Ditch queries. Use arrays of objects (which could be lightweight structs).
Build some grouping mechanism into a for() loop, eg:

for (row in result; group on ‘col’){
// each distinct col value
for {
// each row with same col value
}
}

  • ditch cfm based custom tags, we have support for component based custom

tags

Agreed. Although I think I know of one thing the CFC-based ones don’t seem
to support that the tag-based ones do, however I need to do some more
research on that before raising it.

  • ditch “var” ( I know people love var, I do it as well, but it makes now

sense, the “local” scope is the one following the logic of the language)

Yup. New variables declared within a block are local to the block, unless
otherwise specified.

  • if we already on this topic, ditch the argument scope, we only need one

local scope for functions.

Disagree here. It’s handy to have a collection of all arguments, and that
might as well be the current arguments scope. People just need to stop
bloody actively scoping their arguments. It’s pointless.

  • ditch the variables scope in components and make the this scope private

by default.

Yup. Classes (and they should be classes, not components) should be able to
have public properties, that said. But this is implemented by declaring a
property as public.

  • scope cascading to strict

If that means “do not do any scope cascading” then yes.

[everything I omitted I either agree with or don’t care about]On 8 February 2015 at 08:18, Andrew Penhorwood <@Andrew_Penhorwood> wrote:


Adam

That opens an interesting question.

Also bear in mind that the people who actually do get to decide these things are the association members (or a subset of them on the language advisory), not just us hoi polloi who Micha opens a vote for. And I think offering a voting mechanism kinda implies the majority vote will get their decision actioned, which won’t be the case.

I’d strongly argue that just by virtue of being an association member (which people could be for various reasons: interest in the platform, depending on Lucee for their product, marketing reasons because it comes with a big logo on the website etc), members are not necessarily qualified technically to make any decision on a language spec or language features. I’m not saying they couldn’t as well be qualified to make those decisions, but that’s by far not a given.

Going with such a model would take the language right back to an Allaire/MM/Adobe-approach — “Yeah, that looks cool, I can use that for XYZ, let’s build it” — I assume Micha would veto stupid member decisions anyway though.

What Lucee needs is an independant technical/language steering group led by Micha and Igal, however such a group would be formed and it should be comprised of people who know multiple languages and paradigms and in a perfect world have done language spec work before (at least I know one very good candidate on this mailing list). But organisation membership should for the above reasons not be a criteria for such a language steering group at all.

Cheers
Kai

I have a wishlist of my own, maybe things already in the pipeline?

  • Do away with 1-based arrays. It’s just plain annoying now.

  • What about deprecating direct access to some scopes ( session,
    application, server, cluster ) in favor of access through a built-in facade
    that could ensure locking. If a straetgy of RAD is help the programmer by
    taking care of low level tasks that seems like a logical move.

  • How about a templating system like Mustache that separates logic from
    display? It could be in an extension. Inline logic in cfm pages has always
    been a doubled-edged sword, and in part enabled the “toy” moniker ACF has
    carried for so long.On Sunday, February 8, 2015 at 12:18:44 AM UTC-8, Andrew Penhorwood wrote:

This is a continuation from the tread Outsider perspective
https://groups.google.com/forum/?hl=en#!topic/lucee/5Ol7vTOm6Gk[101-125-false] which
was getting long and fragmented.

Here are some suggestions off-the-cuff from Micha (see the other tread for
context).

So what should a .lucee do better in all this cases.

  • ditch cfoutput-query, it is useless
  • lucee is already passing arrays by ref, so no need to change here
  • ditch cfm based custom tags, we have support for component based
    custom tags
  • ditch “var” ( I know people love var, I do it as well, but it makes now
    sense, the “local” scope is the one following the logic of the language)
  • ditch all the bullshit the local scope does for backward compatibility.
  • if we already on this topic, ditch the argument scope, we only need one
    local scope for functions.
  • ditch the variables scope in components and make the this scope
    private by default.
  • ditch application.cfm of course.
  • ditch dot notation upper case
  • scope cascading to strict
  • … And lot more
  • Then the conversion centered around local vs var in cffunction? I
    am not attached to var or Local but I like fast and I like being able to
    put thing into the variables scope inside the CFComponent. What makes
    sense from a technical perspective? I also like the idea of doing away
    with the argument scope. There would just be a local scope or a function
    scope.

  • I think most people want to see looping cfoutput go away. For me I
    have never used cfoutput group unless it was forced on me by the creator of
    the original code.

  • Application.cfm & OnRequestEnd.cfm should be removed -
    Application.cfc makes more sense.

Andrew Penhorwood

My suggestion to move it to a better communication platform was not about
voting. Though I am not against voting. It is being able to see the
discussion about a change / idea / etc all in one place without having to
filter thought about of other stuff. For example: If we used the bug
tracking system or something else. There would be the “changes to
queries”. Then that discussion would be open to anyone to give their
opinion, idea ,etc but we it would be limited to just queries. Here in the
groups it is hard to see what people are replying too.

Andrew PenhorwoodOn Sunday, February 8, 2015 at 12:50:44 PM UTC-5, Micha wrote:

I life in a country with direct democracy, that means that the people are
voting about everything, mostly with no deep background knowledge, what
sometime brings the politics in real trouble, but mostly we end with very
wise decisions on a long run.

Micha

I completely agree on that, that is the reason I suggested strict as scope
cascading mode, with strict you don’t have to scope the nearest scopes
(arguments, local,variables) but all the ohers.
So #susi# looks for Susi in local and arguments , but not in
url,form,cgi,cookie… What i silly and slow.

MichaOn Sunday, February 8, 2015, Dan Kraus <@Dan_Kraus> wrote:

Question for people pushing for local scope, is it being suggested that we
should also prefix all our variables like “local.foo” everywhere in actual
code. Because I LOATHE that. Even your simple functions become noisy with
cruft that totally hurts readability. It drives me nuts to see every
variable prefixed with “local” or ",“variables”. I understand why people do
it because CF can exhibit some weird or unseen scope creep/cascades not
always expected.

Variable defined in a function should be local to only that function.
Arguments included. I don’t see a reason to have its own scope. If you’re
having name conflicts and need to separate them by scope, its probably poor
design. My own code, I use the arguments scope just to force CF to look
where it should be and not do any scope traveseral. But its annoying and
just gets in the way of writing succinct code.


You received this message because you are subscribed to the Google Groups
“Lucee” group.
To unsubscribe from this group and stop receiving emails from it, send an
email to lucee+unsubscribe@googlegroups.com <javascript:;>.
To post to this group, send email to lucee@googlegroups.com <javascript:;>
.
To view this discussion on the web visit
https://groups.google.com/d/msgid/lucee/bee38ea7-bbee-4327-a6e0-c504735d6e6e%40googlegroups.com
.
For more options, visit https://groups.google.com/d/optout.

Recordset objects have their benefits though right? Query of queries, enforcing that there are always the same number and order of columns in the structures - I would also expect that they are / could be optimized for the use cases that recordsets are generally used for.

But there’s nothing to stop QoQ running against an array of structs - and it would be very convenient.

What does a query object provide that a raw array of structs does not (in terms of API, not implementation)?

  • qry.recordCount - why not qry.len() which would be consistent with myArray.len()?
  • qry.currentRow - really not needed with for ( var row in qry ) … but see below
  • qry.colname[i] - as noted, at odds with intuitive qry[i].colname expectation, but qry.col(“colname”) would be a reasonable addition
  • query metadata - again qry.metadata() or even getMetadata(qry) would be reasonable

I think the main difference that is left is that the query object’s “columns” have SQL types attached to them. For QoQ purposes that’s a handy thing to have. A stock-standard implementation of Queries as Arrays of Structs wouldn’t be able to provide that, I assume — but could surely be implemented.

Cheers
Kai

I remember when the iPad cames out, I was thinking I don’t need this kind
of device, it’s just a big iphone, but I want to have one anyway because I
love gimmicks.
But today I could not even imagine to have none.

I feel the same about queries, queries maybe something you can easily do
with array of struct, but it is not the same, you loose the 2 dimensional
structure. I see query objects the perfect fit for 2 dimensional, data
container.
When you check out the cfadmin tag you will see that I have chosen this
type a lot as a return type.

My primary language is Java for more than 10 years and I have seen a lot of
code over the years and storing 2 dimensional data in a “array os struct”
is seen as a bad choice for sure, because it does not bound you to a
structure.
Much more common is using a array/list of specific types:
List or Address[] (old style)

Sure that is because Java is strictly typed, but like queries I have also
in this case the “columns” fix, you could also do
List<Map> or Map[]
but that is simply very bad practice and has no place in clean code.

Maybe queries are not perfect, but to handle 2 dimensional data structures
in a untyped languages there is nothing better I know and I do not say that
because I only know cfml and nothing else.

To make it short, array of struct is a bad replacement for queries, array
of components is a overkill, of course I’m open for suggestions to replace
queries or improve it, but please not with array of structs or array of
components.

Micha>
On Sunday, February 8, 2015, Sean Corfield <@Sean_Corfield> wrote:

On Feb 8, 2015, at 8:41 AM, Ryan Guill <@Ryan_Guill <javascript:;>> wrote:

What is the benefit in ditching queries? It seems like the perfect
abstraction for a recordset. If you want to work with them as arrays of
structs, why not provide an easy way to convert from one to the other?

I think people are missing the point here. The issue is consistency:
queries are almost like arrays of structs except when they’re not. This
is intuitive:

    for ( var row in myquery ) { … row.col … }

but this is not:

    for ( var i = 1; i <= myquery.recordcount; ++i ) { …

myquery.col[i] … }

If iterating over the query gives you rows in the first case, why isn’t it
query[i].col in the second case? And then look at the original loop over a
query:

    <cfloop query="myquery"> <!— why not "#query#" here? —>
            … #myquery.col# … <!— behaves like row.col in first piece

of code —>

Are you going to try to convince me that’s consistent?

I personally like scopes, especially the local scope, as a way to group
variables together. It’s one of the things I miss from CFML when writing
just about any other language. It is super conventient to be able to
writedump(local); when debugging.

Having crappy debugging tools available to us isn’t a good argument for
perpetuating a weird feature - named scopes - that other languages have
very sensibly chosen not to provide. The fact that “just about any other
language” doesn’t have this feature should make you question why, not
bemoan that other languages don’t have this strange unique-to-CFML feature.

Most other languages out there were designed. CFML was not. If CFML
alone has a particular feature, it probably flies in the face of good
language design.

Which is also why a simple vote on language features from a population
largely void of any language design skills has to potential to produce
weird results… If all your first / primary language is CFML and you don’t
have much experience of other languages in large production systems, you’re
probably going to vote for CFML features that other languages have made
conscious designs to avoid.

Sean Corfield – (904) 302-SEAN
An Architect’s View – http://corfield.org/

“Perfection is the enemy of the good.”
– Gustave Flaubert, French realist novelist (1821-1880)


You received this message because you are subscribed to the Google Groups
“Lucee” group.
To unsubscribe from this group and stop receiving emails from it, send an
email to lucee+unsubscribe@googlegroups.com <javascript:;>.
To post to this group, send email to lucee@googlegroups.com <javascript:;>
.
To view this discussion on the web visit
https://groups.google.com/d/msgid/lucee/8C1B4EEE-8708-4937-B9F8-D849D4628CE0%40corfield.org
.
For more options, visit https://groups.google.com/d/optout.

between the lines

Sorry, seems I mixed you with Adam :wink:

:slight_smile:

I agree that it is odd that you do in cfml
Query.column.row
And not
query.row.column
BUT (1) mostly I see in cml only
Query.column
Many people are not even aware that you can do
Query.column.row
BUT (2) why exactly is row.column the better choice? Because this is in
other languages the case where this has a techical backgrounds?

I’m not sure I understand you (sorry).

Here’s a specific question that might help focus on my concern:

    for ( var row in myquery ) …

That works and implies myquery is a sequence of rows

nope it is not, a query is a collection of columns, when we implemented the
query object there was no support for the construct above a query objects
acts always as query.column.row
#query.firstname[1]# <!— outputs the first row of the column first name
—>
Lucee is using a warpper class to simulate your code example …

(and that each row is an associative structure whose keys are column
names). In other words, it behaves as if you could say
myquery[n][“colname”] - which you cannot, currently.

nope
https://bitbucket.org/lucee/lucee/src/e6ffd51e0eb0c16d730fc9bf9f6364df8bb63792/lucee-java/lucee-core/src/lucee/runtime/type/QueryImpl.java?at=master#cl-131

But we have myquery[“colname”][n] as the actual way you index into a query
object. That implies myquery is an associative structure (the keys are
column names) and each column is an array (indexed by numbers).

more or less yes, it is a little bit more complicated because CFML has a
lot of special behavior when it comes to queries, but this is an other
story… (working example:
#query.columnName.columnName.columnName.columnNam.# )

When you loop over an associative structure, you do:

    for ( var key in mystruct ) …

So if myquery is really associative, you would expect:

    for ( var colname in myquery ) …

Hence the inconsistency. It behaves like an array in one case but like a
struct in another.

i totally agree that there is a lot of inconsistency in that sector, even
worse is cfloop …

In particular, what should myquery.map( somefn ) do? Should it map over
the rows (and process each “struct”) or should it map over the columns (and
process each “array”)?

The underlaying implementation should not dicate the functionality, we can
change the unerlaying implemtnation that is not a big deal.
What matters is the user expierence, so what is the best way to handle 2
dimensonal data structures and this IN MY OPINION cfoutput/cfloop today
i myself use never a “for” loops at all in my cfml code, i prefer “loop”!
loop(query=myquery) {
echo(myQuery.firstname);
}
loop( array=arr index=“i” item=“v”){
}

nothing is simpler and faster than this!

What I’m proposing is to codify the behavior in terms of a well-understood
interface - and I’m suggesting an Indexable one, like an array - and then
add a method to obtain a named column as an array.

to be honest I (again my personal opinion) see that as a step backward!

That way it become clear exactly what for ( var thing in myquery ) …
should do. And by extension what myquery.map( somefn ) should do as well.

i never saw onces the question in the mailing list, that someone needs
explanation to use a query…
so i think we have not a big problem with that.

And you can still easily treat a query object as a collection of columns
(arrays of values) but you would need to be explicit about it by calling a
method:

    myquery.getColumn( "colname" )
    myquery.getColumnNames() // which already works I believe?

in what way is that better than simply do
myQuery.colname
myQuery.columnlist()

what is the most common task with queries, in all my cfml code i have only
a couple of rows where im really intrested in a certain line and then i
used mostly querySlice.

Remember that almost the only place you normally see myquery.colname is
inside a cfloop query= which is already a somewhat peculiar construct
(takes a query variable name, not value; manipulates currentrow “behind
the scenes”; treats the query name like a scope qualifier inside the loop).

If a loop tag continues in Lucee, I’d suggest something like this for a
query:

    <lc:loop item="row" collection="#myquery#">
            … #row.colname# ...
    </lc:loop>

in my opinion we should retire “implcit query invocation” (what is a
setting in lucee), so you have always to write
#query.column# or #query.column[row]#

looping a query is btw extremly similar to looping a collection in java,
where you also have a internal pointer in the object, and you don’t have to
take care for a index (row), what is also the most common way to loop in
Java!

in the direct approach with for:
List list=getList();
for(String str:list){
System.out.println(str);
}

or more the classic way:
List list=getList();
while(it.hasNext()){
String str=it.hasNext();
System.out.println(str);
}

in both examle you don’t use a counter, of course we talk here about one
dimensonal structures,
but like i have writte before i see the something like this as equivalent
of queries in Java
class Address {
public final firstName;

public Address(String firstName,…) {this.firstName=firstName;…}
}
List addresses=getList();
for(Address address: addresses){
System.out.println(address.firstname);
}
what is nearly the same as
addresses=getList();
loop(query=addresses){
echo(addresses.firstname);
}

(just to emphasize that a consistently loop-over-the-rows approach is what
I’m looking for)

If this still hasn’t clarified things, I think I’ll give up… :frowning:

I’m sorry for that!
That i disagree does not mean i don’t get your point, i simply see the
focus on this different.
Different languages have different approch to do things and i simply see
the CFML approach in this case very good, better than other languages do!
that does not mean that other approaches are wrong, but rewrite everything
just to make it good in a other way seems to me a waste of time.

just my 2rp (2c)
MichaOn Mon, Feb 9, 2015 at 8:06 AM, Sean Corfield <@Sean_Corfield> wrote:

On Feb 8, 2015, at 10:43 PM, Michael Offner <@Michael_Offner> wrote:

Sean Corfield – (904) 302-SEAN
An Architect’s View – http://corfield.org/

“Perfection is the enemy of the good.”
– Gustave Flaubert, French realist novelist (1821-1880)


You received this message because you are subscribed to the Google Groups
“Lucee” group.
To unsubscribe from this group and stop receiving emails from it, send an
email to lucee+unsubscribe@googlegroups.com.
To post to this group, send email to lucee@googlegroups.com.
To view this discussion on the web visit
https://groups.google.com/d/msgid/lucee/B4199D86-BE96-40AB-984C-23CF50BB67E9%40corfield.org
.
For more options, visit https://groups.google.com/d/optout.

Sorry, seems I mixed you with Adam :wink:
I agree that it is odd that you do in cfml
Query.column.row
And not
query.row.column
BUT (1) mostly I see in cml only
Query.column
Many people are not even aware that you can do
Query.column.row
BUT (2) why exactly is row.column the better choice? Because this is in
other languages the case where this has a techical backgrounds?

MichaOn Monday, February 9, 2015, Sean Corfield <@Sean_Corfield> wrote:

Gah! You’re missing my point as well!

I’m not saying replace query objects with array of structs - just make
them behave consistently like an array of structs when you’re iterating
over them and accessing elements of them.

We already have for ( var row in myquery ) … and row looks like a struct
and that’s great. But let’s consistently have myquery[n] behave like row n,
and streamline the language to make query objects fit better as a
collection type.

Heck, I’m happy with myquery.colname behaving like an array as well (so a
query is both an array of structs and a struct of arrays).

I don’t want the implementation to change, I want the interface to be
a more consistent set of collection “classes”.

Does that help clarify what I’m talking about?

In Clojure terms, I want a query object to be Countable, Indexable,
Associative…

Sean

On Feb 8, 2015, at 10:17 PM, Michael Offner <@Michael_Offner <javascript:;>> wrote:

My primary language is Java for more than 10 years and I have seen a lot
of code over the years and storing 2 dimensional data in a “array os
struct” is seen as a bad choice for sure, because it does not bound you to
a structure.
Much more common is using a array/list of specific types:
List or Address[] (old style)

Sure that is because Java is strictly typed, but like queries I have
also in this case the “columns” fix, you could also do
List<Map> or Map[]
but that is simply very bad practice and has no place in clean code.

Maybe queries are not perfect, but to handle 2 dimensional data
structures in a untyped languages there is nothing better I know and I do
not say that because I only know cfml and nothing else.

To make it short, array of struct is a bad replacement for queries,
array of components is a overkill, of course I’m open for suggestions to
replace queries or improve it, but please not with array of structs or
array of components.


You received this message because you are subscribed to the Google Groups
“Lucee” group.
To unsubscribe from this group and stop receiving emails from it, send an
email to lucee+unsubscribe@googlegroups.com <javascript:;>.
To post to this group, send email to lucee@googlegroups.com <javascript:;>
.
To view this discussion on the web visit
https://groups.google.com/d/msgid/lucee/6DC15FAA-42B3-45D8-8CA3-3E63522C3861%40corfield.org
.
For more options, visit https://groups.google.com/d/optout.

Gah! You’re missing my point as well!

I’m not saying replace query objects with array of structs - just make them behave consistently like an array of structs when you’re iterating over them and accessing elements of them.

We already have for ( var row in myquery ) … and row looks like a struct and that’s great. But let’s consistently have myquery[n] behave like row n, and streamline the language to make query objects fit better as a collection type.

Heck, I’m happy with myquery.colname behaving like an array as well (so a query is both an array of structs and a struct of arrays).

I don’t want the implementation to change, I want the interface to be a more consistent set of collection “classes”.

Does that help clarify what I’m talking about?

In Clojure terms, I want a query object to be Countable, Indexable, Associative…

SeanOn Feb 8, 2015, at 10:17 PM, Michael Offner <@Michael_Offner> wrote:

My primary language is Java for more than 10 years and I have seen a lot of code over the years and storing 2 dimensional data in a “array os struct” is seen as a bad choice for sure, because it does not bound you to a structure.
Much more common is using a array/list of specific types:
List or Address[] (old style)

Sure that is because Java is strictly typed, but like queries I have also in this case the “columns” fix, you could also do
List<Map> or Map[]
but that is simply very bad practice and has no place in clean code.

Maybe queries are not perfect, but to handle 2 dimensional data structures in a untyped languages there is nothing better I know and I do not say that because I only know cfml and nothing else.

To make it short, array of struct is a bad replacement for queries, array of components is a overkill, of course I’m open for suggestions to replace queries or improve it, but please not with array of structs or array of components.

But you can treat queries like an array of structs if thats what you’d like to do, you don’t have to use the inconsistent syntax. But if the api of the recordset needs tweaks, lets do that.

You’re still missing my point.

Recordset objects have their benefits though right? Query of queries, enforcing that there are always the same number and order of columns in the structures - I would also expect that they are / could be optimized for the use cases that recordsets are generally used for.

But there’s nothing to stop QoQ running against an array of structs - and it would be very convenient.

What does a query object provide that a raw array of structs does not (in terms of API, not implementation)?

  • qry.recordCount - why not qry.len() which would be consistent with myArray.len()?
  • qry.currentRow - really not needed with for ( var row in qry ) … but see below
  • qry.colname[i] - as noted, at odds with intuitive qry[i].colname expectation, but qry.col(“colname”) would be a reasonable addition
  • query metadata - again qry.metadata() or even getMetadata(qry) would be reasonable

Note that there’s nothing inherently problematic in having a query object have methods and yet still implement the same API as an array (in terms of iteration and indexing). I’m not suggesting query objects go away completely, just that they conform to an “array of structs” API in terms of behavior - they could still have additional methods to afford the conveniences people like about query objects.

For folks who want indexes when looping over arrays - or queries - what about an extension to for loops like this:

for ( var (elem,ix) in myArray ) {
	… elem is the element, ix is the index (1..)
}

for ( var (row,ix) in myQuery ) {
	… row is the row(!), ix is the row number (1..)
}

Sean Corfield – (904) 302-SEAN
An Architect’s View – http://corfield.org/

“Perfection is the enemy of the good.”
– Gustave Flaubert, French realist novelist (1821-1880)On Feb 8, 2015, at 1:14 PM, Ryan Guill <@Ryan_Guill> wrote:

Sorry, seems I mixed you with Adam :wink:

:slight_smile:

I agree that it is odd that you do in cfml
Query.column.row
And not
query.row.column
BUT (1) mostly I see in cml only
Query.column
Many people are not even aware that you can do
Query.column.row
BUT (2) why exactly is row.column the better choice? Because this is in other languages the case where this has a techical backgrounds?

I’m not sure I understand you (sorry).

Here’s a specific question that might help focus on my concern:

for ( var row in myquery ) …

That works and implies myquery is a sequence of rows (and that each row is an associative structure whose keys are column names). In other words, it behaves as if you could say myquery[n][“colname”] - which you cannot, currently.

But we have myquery[“colname”][n] as the actual way you index into a query object. That implies myquery is an associative structure (the keys are column names) and each column is an array (indexed by numbers).

When you loop over an associative structure, you do:

for ( var key in mystruct ) …

So if myquery is really associative, you would expect:

for ( var colname in myquery ) …

Hence the inconsistency. It behaves like an array in one case but like a struct in another.

In particular, what should myquery.map( somefn ) do? Should it map over the rows (and process each “struct”) or should it map over the columns (and process each “array”)?

What I’m proposing is to codify the behavior in terms of a well-understood interface - and I’m suggesting an Indexable one, like an array - and then add a method to obtain a named column as an array.

That way it become clear exactly what for ( var thing in myquery ) … should do. And by extension what myquery.map( somefn ) should do as well.

And you can still easily treat a query object as a collection of columns (arrays of values) but you would need to be explicit about it by calling a method:

myquery.getColumn( "colname" )
myquery.getColumnNames() // which already works I believe?

Remember that almost the only place you normally see myquery.colname is inside a cfloop query= which is already a somewhat peculiar construct (takes a query variable name, not value; manipulates currentrow “behind the scenes”; treats the query name like a scope qualifier inside the loop).

If a loop tag continues in Lucee, I’d suggest something like this for a query:

<lc:loop item="row" collection="#myquery#">
	… #row.colname# ...
</lc:loop>

(just to emphasize that a consistently loop-over-the-rows approach is what I’m looking for)

If this still hasn’t clarified things, I think I’ll give up… :frowning:

Sean Corfield – (904) 302-SEAN
An Architect’s View – http://corfield.org/

“Perfection is the enemy of the good.”
– Gustave Flaubert, French realist novelist (1821-1880)On Feb 8, 2015, at 10:43 PM, Michael Offner <@Michael_Offner> wrote:

Right, the bare array of structs wouldn’t have that metadata (but the updated query object that behaved like an array of structs still would). So it would be a matter of whether basic SQL-like metadata could be derived from the data in a bare array of structs - doesn’t something already try to do something similar by inspecting the first row of a query? I’m blanking on where that happens…

Sean Corfield – (904) 302-SEAN
An Architect’s View – http://corfield.org/

“Perfection is the enemy of the good.”
– Gustave Flaubert, French realist novelist (1821-1880)On Feb 8, 2015, at 6:05 PM, Kai Koenig <@Kai_Koenig> wrote:

I think the main difference that is left is that the query object’s “columns” have SQL types attached to them. For QoQ purposes that’s a handy thing to have. A stock-standard implementation of Queries as Arrays of Structs wouldn’t be able to provide that, I assume — but could surely be implemented.

This all makes sense, and I think making the recordset object fit the
interfaces that an array of structs is a great compromise. I personally
like your loop syntax - python has something similar with enumerate() - but
like someone mentioned earlier (possibly a different thread), .each()
,.map() and .reduce() is a much more useful abstraction most of the time.

And perhaps with linkedHashMap structures and safe evaluation operators the
other benefits of recordsets (that column order and existence is
guaranteed) can not be unique either.

Best of both worlds.On Sunday, February 8, 2015 at 7:57:04 PM UTC-6, Sean Corfield wrote:

On Feb 8, 2015, at 1:14 PM, Ryan Guill <ryan...@gmail.com <javascript:>> wrote:

But you can treat queries like an array of structs if thats what you’d
like to do, you don’t have to use the inconsistent syntax. But if the api
of the recordset needs tweaks, lets do that.

You’re still missing my point.

Recordset objects have their benefits though right? Query of queries,
enforcing that there are always the same number and order of columns in the
structures - I would also expect that they are / could be optimized for the
use cases that recordsets are generally used for.

But there’s nothing to stop QoQ running against an array of structs - and
it would be very convenient.

What does a query object provide that a raw array of structs does not (in
terms of API, not implementation)?

  • qry.recordCount - why not qry.len() which would be consistent with
    myArray.len()?
  • qry.currentRow - really not needed with for ( var row in qry ) … but see
    below
  • qry.colname[i] - as noted, at odds with intuitive qry[i].colname
    expectation, but qry.col(“colname”) would be a reasonable addition
  • query metadata - again qry.metadata() or even getMetadata(qry) would be
    reasonable

Note that there’s nothing inherently problematic in having a query object
have methods and yet still implement the same API as an array (in terms of
iteration and indexing). I’m not suggesting query objects go away
completely, just that they conform to an “array of structs” API in terms of
behavior - they could still have additional methods to afford the
conveniences people like about query objects.

For folks who want indexes when looping over arrays - or queries - what
about an extension to for loops like this:

    for ( var (elem,ix) in myArray ) { 
            … elem is the element, ix is the index (1..) 
    } 

    for ( var (row,ix) in myQuery ) { 
            … row is the row(!), ix is the row number (1..) 
    } 

Sean Corfield – (904) 302-SEAN
An Architect’s View – http://corfield.org/

“Perfection is the enemy of the good.”
– Gustave Flaubert, French realist novelist (1821-1880)

Agreed. There are plenty of people qualified to make suggestions or be used
as a sounding board for ideas, but ultimately a small group of the most
qualified people should be responsible for guiding the language
specification. I don’t think the wisdom of crowds applies in this space.
Most of us don’t have the knowledge, training, and experience it takes to
make those sorts of decisions.On Sunday, February 8, 2015 at 1:52:27 PM UTC-8, Kai Koenig wrote:

What Lucee needs is an independant technical/language steering group led
by Micha and Igal, however such a group would be formed and it should be
comprised of people who know multiple languages and paradigms and in a
perfect world have done language spec work before (at least I know one very
good candidate on this mailing list). But organisation membership should
for the above reasons not be a criteria for such a language steering group
at all.

Cheers
Kai