On 1/30/19 1:59 PM, Richard Hipp wrote:
It seems that you distinguish between the xStep and xFinal methods by
the number of argments.  xStep [has] 1+N argument (where N is the
number of function parameters) and xFinal has just 1.

Yes.  I was explicit about that in my first email.

Dan suggests (and I agree) that this will not extend well to window
functions.

I agree too.  Trouble is, I designed around aggregate functions while
disregarding window functions because of my total lack of experience
with window functions.

It might be better to have an initial argument that is the
"method" name.

I did initially consider this but decided it was not necessary for
aggregate functions because final will always have zero arguments
whereas step will never usefully have zero arguments.

xStep would 2+N arguments where the first argument is the string
"step" and xFinal has 2 arguments where the first argument is "final".
Then when you go to add the xValue and xInverse routines for window
functions, you will have a convenient way to distinguish those calls
from xStep and xFinal.

Adding an extra initial argument to the aggregate functions is not a
difficult thing to do.  I can certainly add that.  I just didn't see it
as useful because it conveys information redundantly provided by another
path guaranteed to be there.

Again, I agree it leaves room for future expansion, but (1) it's highly
unlikely that the fundamental definition of an aggregate function will
change, and (2) I don't think it's strictly necessary that the same
calling convention be used for aggregate functions and window functions.

My preference would be that all functions, regardless of kind, have the
same convention, but this is not possible because the interface to
scalar functions is set in stone, and it would be useless to insert a
first argument that's always "function".  Therefore, since aggregate
functions must be defined differently than scalar functions, I thought
it would be fine for window functions to be defined differently than
aggregate functions.

The next chance I get (probably tomorrow morning), I'll go ahead and add
"step" or "final" as the initial argument to aggregate functions.  I'll
also lift the prohibition on aggregate functions with no arguments.

All my above reasoning notwithstanding (I just wanted to document why I
took the approach I did), this change does benefit aggregate functions
by making it easier to tie into TclOO and similar Tcl object systems
which use initial arguments as method names.  As for procedures that
don't need this, they are free to ignore the argument.

Old example, works with current code, here for baseline comparison:

db function list -deterministic -aggregate {
    apply {{state args} {
        concat $state $args
    }}
}

New example:

db function list -deterministic -aggregate {
    apply {{method state args} {
        concat $state $args
    }}
}

Alternately:

db function list -deterministic -aggregate {
    apply {{method state args} {
        switch $method {
            step {concat $state $args}
            final {set state}
        }
    }}
}

Or:

namespace eval ListAggregate {
    namespace export step final
    namespace ensemble create
    proc step {state args} {
        concat $state $args
    }
    proc final {state} {
        return $state
    }
}
db function list -deterministic -aggregate ListAggregate

Or:

oo::class create ListAggregate
oo::objdefine ListAggregate {
    method step {state args} {
        concat $state $args
    }
    method final {state} {
        return $state
    }
}
db function list -deterministic -aggregate ListAggregate

Or:

oo::class create ListAggregate {
    method step {state args} {
        concat $state $args
    }
    method final {state} {
        my destroy
        return $state
    }
}
db function list -deterministic -aggregate [ListAggregate new]

Though I do not prefer that final example since it creates heavyweight
infrastructure to hold per-instance internal state, yet doesn't actually
make use of it.  However, this could be useful as an alternative to
storing state data in the return value, making it possible to modify it
in-place without incurring copy-on-write, as documented in the
tclSqlFuncStep() comments.

Overall, my preference is to avoid creating global named objects when
anonymous values will do the job, hence my use of [apply].

--
Andy Goth | <andrew.m.goth/at/gmail/dot/com>
_______________________________________________
sqlite-users mailing list
sqlite-users@mailinglists.sqlite.org
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users

Reply via email to