Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New functions fn:foot, fn:truncate, array:foot, array:truncate #250

Merged
merged 2 commits into from
Dec 7, 2022

Conversation

michaelhkay
Copy link
Contributor

New functions fn:foot, fn:truncate, array:foot, array:truncate, as proposed in issue #97. Note that not everyone was happy with the name "truncate".

@ndw
Copy link
Contributor

ndw commented Nov 17, 2022

Is it worth adding an optional length parameter?

fn:head((1,2,3)) = 1
fn:head((1,2,3),1) = 1
fn:head((1,2,3),2) = (1,2)

etc.

Similar effects could be obtained in the related funtions (including fn:tail). This can be extended further with negative numbers,

fn:head((1,2,3), -1)  = (1,2)

Where +n means the first n items and -n means all but the last n items. This is not a new idea, it's what the Linux head command does.

@ChristianGruen
Copy link
Contributor

Is it worth adding an optional length parameter?

Personally, I would prefer to keep head, tail, foot and truncate simple and straightforward. I think that the new fn:slice function (and, in some cases, fn:subsequence) provides good ways to return subsequences with both positive and negative offsets?

@ndw
Copy link
Contributor

ndw commented Nov 17, 2022

Fair enough, @ChristianGruen. I'm fine with keeping it simple, just thought I'd raise the thought because it occurred to me.

@michaelhkay
Copy link
Contributor Author

I had the same thoughts myself ((a) adding a length argument, and (b) better to keep it simple and have an fn:slice that's all-singing-and-dancing).

@PieterLamers
Copy link

My objection against truncate would be that I know it from Sql where it means to clear entirely. If I understand correctly it would have the following meaning here: all but last. And the point that it is a verb is also speaking against simplicity and symmetry. But hey, for me tail was never intuitive either as it suggests some (small) end, not everything but the first.

@ChristianGruen
Copy link
Contributor

If the majority of the readers of my comment can guess what fn:daeh and fn:liat is supposed to say, these could be alternatives ;·)

@ndw
Copy link
Contributor

ndw commented Nov 17, 2022

I asked my resident linguist for alternative pairs to go with foot. Among the options proposed: body/foot, trunk/foot, axon/terminal (nah), bulk/tailend (there's a joke about the ends of bells in there somewhere, but I can't find it), and tentacle/sucker. I'm reliably informed that the last was a joke.

@michaelhkay
Copy link
Contributor Author

"head" and "foot" is a very familiar pairing in the document/publishing world inhabited by many of our users, so I see no problem with it.

I'm personally happy with truncate because it matches the natural-language meaning of "cut off the end" and because I can't think of anything better. My next choice would be remove-last(), reflecting the existing usage of "remove" and "last" in the language.

It would be a mistake to ignore the cultural traditions of the language we are curating. The nomenclature tradition is to avoid quirkiness, jocularity, and excessive brevity, but at the same time to avoid excessive pedantry. Function names can be verbs (translate), verb-noun combinations (parse-json, resolve-uri, is-NaN), nouns (head, tail, subsequence, root), adjectives (size, string-length, upper-case) or pretty well anything else, but they are invariably combinations of one or more meaningful English words or common words of art such as "URI"; the only exceptions are where we have borrowed well known function names from other languages, such as avg and cos, min and max.

@ndw
Copy link
Contributor

ndw commented Nov 17, 2022

I was just exploring the design space a bit. I concur that nothing really pairs with "foot" and has the same strength of analogy as head/tail. I can live with truncate. I could live with remove-last, but I think I have a marginal preference for truncate.

@ChristianGruen
Copy link
Contributor

I could live with remove-last, but I think I have a marginal preference for truncate.

Me too. If we had remove-last, user might look for remove-first.

Copy link
Contributor

@ChristianGruen ChristianGruen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe item in a sequenceitem of a sequence ?

@PieterLamers
Copy link

PieterLamers commented Nov 23, 2022

I have a few remarks I would like to make. First, I still believe that head + tail is badly chosen, as the body is missing in the equation. A novice will need to learn that tail means anything but the head rather than something dangling at the end (after the body). This makes the term tail non-trivial. remove-first or skip-first would have been a much better choice. On the subject of verbs: I know there are verbs in the language (duh) and I am not against them, I am against interfering in a proposed symmetrical solution using a verb where the other terms in use are all nouns. My proposal would be to add first + skip-first, and last + skip-last and to deprecate head + tail, removing any supposed real-world analogies (and keep them on as synonyms until the last generation of head-tail users have retired). remove-first is also fine. As @ChristianGruen says: the user would expect a remove-first if we had remove-last. Having that symmetrical would actually help users learning the vocabulary. As with spoken languages, we should be able to improve the terms, not just add new ones. If we want to augment the vocabulary to fill gaps in the paradigm and to help adoption, we should also be willing to sacrifice some of the pseudo-real-world analogies.
So my suggestions: use first+last, or initial+final, or start+end for current (and proposed) head and foot, and remove-* or skip-* for the tail and truncate terms.

@michaelhkay
Copy link
Contributor Author

@PieterLamers The terms "head" and "tail" are well established in other functional programming languages, and now in XPath 3.1, and there is absolutely no point in changing them even if we were convinced they could be improved.

(If there is one existing function name I would like to change, it is "contains()", but the fact that 95% of users use it correctly and 5% incorrectly isn't a sufficient case for changing it).

For anyone working with documents, "head()" and "foot()" are very natural complements for the beginning and end of something; everyone knows what headers and footers are. And last() is already taken.

For truncate(), I suggest that if we can't find a term that everyone finds acceptable, we simply drop the idea. It's easy enough to live without it.

@ChristianGruen
Copy link
Contributor

For truncate(), I suggest that if we can't find a term that everyone finds acceptable, we simply drop the idea. It's easy enough to live without it.

A strong +1 for keeping it. I see many use cases for having reverse versions of head and tail (and we have functions like fold-right, items-after, which could as well have been realized with additional reverse function calls).

Still, the function is not essential enough to spend much more time on finding a/the perfect name.

@ChristianGruen
Copy link
Contributor

It’s entertaining to see that our discussion has, of course, been held for other programming languages before. Maybe some of you know car and cdr from Lisp: https://irreal.org/blog/?p=8500

Lisp provides a butlast function for all but the last item(s). I won’t speak up for but-foot.

But I tend to claim that no one has come up with a flawless solution, and I’d be happy with both a self-explanatory truncate or a Haskell-like init.

@Arithmeticus
Copy link
Contributor

My two cents on the naming issue.

truncate is the only of the four functions that is a verb. That inconsistency is disorienting. If three of the functions are nouns, the fourth should be as well.

The programmer is invited to think of sequences with an anatomical metaphor with head and tail, which are set in stone (or flesh and bone as it were). Fair enough. But foot introduces great confusion into the metaphor. Does the tail have a foot or the foot have a tail? What animal is to be conjured? Fictive illuminations from medieval bestiaries, or a Terry Gilliam cartoon, spring to mind.

I recommend for the complement of head & tail we either (1) stay within the confines of this anatomical metaphor or (2) find some other metaphor space that is unrelated to anatomy or (3) avoid metaphor.

Possibilities for (1):
fn:tail-tip() and fn:all-but-tail-tip()
fn:tail-end() and fn:all-but-tail-end()

Possibilities for (2):
fn:caboose() and fn:without-caboose()
fn:stub() and fn:without-stub()

Possibilities for (3)
fn:end() and fn:all-but-end() (though fn:endless() would be funny)
fn:last-item() and fn:all-but-last-item()

@michaelhkay
Copy link
Contributor Author

I think it's only disorienting because you're thinking of the four functions as a group. If you think of truncate() as a special case of remove(), it ceases to be a problem.

Of course, we could get used to stem(). In the end, all names are arbitrary, and they cease to seem odd once they have become familiar. I prefer truncate() though on the grounds that someone reading the code is more likely to make a correct guess as to what the function does, which to me is probably the most important test.

@ChristianGruen
Copy link
Contributor

In the end, all names are arbitrary, and they cease to seem odd once they have become familiar.

Exactly. I would be happy with init, truncate and stem.

@Arithmeticus
Copy link
Contributor

If that were the direction, I would opt for truncate(), but also request it come with a 1-arity version where a user can specify the point at which to do the truncation. Truncating is the cutting of an arbitrary number of final items, not merely the last.

Of the options I provided I think that fn:last-item() is best, because it resonates with the existing fn:last(), which is the function programmers are fishing around for in this use-case.

@Arithmeticus
Copy link
Contributor

Oops, I meant a 2-arity version of truncate().

It makes me wonder if the complement of truncate() couldn't itself also be a verb, and allow a 2-arity version so that the user can specify how much of the end to retain. That would be a great benefit to those of us who have to jigger with last() when trying to get an arbitrary number of final items via subsequence().

@ChristianGruen
Copy link
Contributor

ChristianGruen commented Nov 29, 2022

It makes me wonder if the complement of truncate() couldn't itself also be a verb, and allow a 2-arity version so that the user can specify how much of the end to retain.

fn:slice might provide that.

My personal hope would have been to have a symmetric counterpart for tail which allows us to reverse code that’s written with head and tail, similarly to how it can be done in Haskell or Lisp. Some examples for that can e.g. be found here: #80 (comment).

@michaelhkay
Copy link
Contributor Author

For more flexibile functions, we should look again at things like fn:slice(2, -1) (=tail()), fn:slice(1, -2) (=truncate()), fn:slice(-5, -1) (select the last five), fn:slice(5, -1) (select all but the first four).

@ndw ndw self-requested a review December 7, 2022 10:03
@ndw
Copy link
Contributor

ndw commented Dec 7, 2022

Agreed in principle at meeting 014 on 6 December 2022. Merging with two approvals.

@ndw ndw merged commit 0334d0a into qt4cg:master Dec 7, 2022
@michaelhkay michaelhkay deleted the Issue97-foot-etc branch July 8, 2023 22:05
@michaelhkay michaelhkay added XQFO An issue related to Functions and Operators Tests Added Tests have been added to the test suites Completed PR has been applied, tests written and tagged, no further action needed labels Mar 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Completed PR has been applied, tests written and tagged, no further action needed Tests Added Tests have been added to the test suites XQFO An issue related to Functions and Operators
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants