1
0
mirror of https://github.com/janet-lang/janet synced 2024-12-26 08:20:27 +00:00

Rename contains? and contains-key? to has-value? and has-key?

Shorten docstrings to be less like a tutorial. They get put into RAM
and memory ain't free.
This commit is contained in:
Calvin Rose 2023-05-31 22:35:14 -05:00
parent 0fcbda2da7
commit 5de889419f
2 changed files with 47 additions and 77 deletions

View File

@ -1197,45 +1197,15 @@
~(def ,alias :dyn ,;more ,kw)) ~(def ,alias :dyn ,;more ,kw))
(defn contains-key? (defn has-key?
```Checks if a collection contains the specified key. "Check if a data structure `ds` contains the key `key`."
[ds key]
Semantically equivalent to `(not (nil? (get collection key)))`. (not= nil (get ds key)))
Arrays, tuples, and buffer types (string, buffer, keyword, symbol) are all indexed by integer keys.
For those types, this function simply checks if the index is less than the length.
If this function succeeds, then a call to `(in collection key)` is guarenteed
to succeed as well.
Note that tables or structs (dictionaries) never contain null keys```
[collection key]
(not (nil? (get collection key))))
(defn contains?
```Checks if a collection contains the specified value.
This supports any iterable type by way of the `next` function.
This includes buffers, dictionaries, arrays, fibers, and possibly abstract types.
For tables and structs, this checks the values, not the keys.
For arrays, tuples (and any other iterable type), this simply checks if any of the values are equal.
For buffer types (strings, buffers, keywords), this checks if the specified byte is present.
This is because, buffer types (strings, keywords, symbols) are simply sequences, with byte values.
This means they will also work with `next` and `index-of`.
However, it also means this function will not check for substrings, only integer bytes (which could be unexpected).
In other words is `(contains? "foo bar" "foo")` is always false, because "foo" is not an integer byte
If you want to check for a substring in a buffer, then use `(truthy? (string/find substr buffer))`,
or just `(if (string/find substr buffer) then else)`
In general this function has O(n) performance, since it requires iterating over all the values.
Note that tables or structs (dictionaries) never contain null values```
[collection val]
(not (nil? (index-of val collection))))
(defn has-value?
"Check if a data structure `ds` contains the value `value`. Will run in time proportional to the size of `ds`."
[ds value]
(not= nil (index-of value ds)))
(defdyn *defdyn-prefix* ``Optional namespace prefix to add to keywords declared with `defdyn`. (defdyn *defdyn-prefix* ``Optional namespace prefix to add to keywords declared with `defdyn`.
Use this to prevent keyword collisions between dynamic bindings.``) Use this to prevent keyword collisions between dynamic bindings.``)

View File

@ -33,7 +33,7 @@
(assert (= nil (index-of (chr "a") "")) "index-of 9") (assert (= nil (index-of (chr "a") "")) "index-of 9")
(assert (= nil (index-of 10 @[])) "index-of 10") (assert (= nil (index-of 10 @[])) "index-of 10")
(assert (= nil (index-of 10 @[1 2 3])) "index-of 11") (assert (= nil (index-of 10 @[1 2 3])) "index-of 11")
# NOTE: These is a motivation for the contains? and contains-key? functions below # NOTE: These is a motivation for the has-value? and has-key? functions below
# returns false despite key present # returns false despite key present
(assert (= false (index-of 8 {true 7 false 8})) "index-of corner key (false) 1") (assert (= false (index-of 8 {true 7 false 8})) "index-of corner key (false) 1")
@ -41,36 +41,36 @@
# still returns null # still returns null
(assert (= nil (index-of 7 {false 8})) "index-of corner key (false) 3") (assert (= nil (index-of 7 {false 8})) "index-of corner key (false) 3")
# contains? # has-value?
(assert (= false (contains? [] "foo")) "contains? 1") (assert (= false (has-value? [] "foo")) "has-value? 1")
(assert (= true (contains? [4 7 1 3] 4)) "contains? 2") (assert (= true (has-value? [4 7 1 3] 4)) "has-value? 2")
(assert (= false (contains? [4 7 1 3] 22)) "contains? 3") (assert (= false (has-value? [4 7 1 3] 22)) "has-value? 3")
(assert (= false (contains? @[1 2 3] 4)) "contains? 4") (assert (= false (has-value? @[1 2 3] 4)) "has-value? 4")
(assert (= true (contains? @[:a :b :c] :a)) "contains? 5") (assert (= true (has-value? @[:a :b :c] :a)) "has-value? 5")
(assert (= false (contains? {} :foo)) "contains? 6") (assert (= false (has-value? {} :foo)) "has-value? 6")
(assert (= true (contains? {:a :A :b :B} :A)) "contains? 7") (assert (= true (has-value? {:a :A :b :B} :A)) "has-value? 7")
(assert (= true (contains? {:a :A :b :B} :A)) "contains? 7") (assert (= true (has-value? {:a :A :b :B} :A)) "has-value? 7")
(assert (= true (contains? @{:a :A :b :B} :A)) "contains? 8") (assert (= true (has-value? @{:a :A :b :B} :A)) "has-value? 8")
(assert (= true (contains? "abc" (chr "a"))) "contains? 9") (assert (= true (has-value? "abc" (chr "a"))) "has-value? 9")
(assert (= false (contains? "abc" "1")) "contains? 10") (assert (= false (has-value? "abc" "1")) "has-value? 10")
# weird true/false corner cases, should align with "index-of corner key {k}" cases # weird true/false corner cases, should align with "index-of corner key {k}" cases
(assert (= true (contains? {true 7 false 8} 8)) "contains? corner key (false) 1") (assert (= true (has-value? {true 7 false 8} 8)) "has-value? corner key (false) 1")
(assert (= true (contains? @{false 8} 8)) "contains? corner key (false) 2") (assert (= true (has-value? @{false 8} 8)) "has-value? corner key (false) 2")
(assert (= false (contains? {false 8} 7)) "contains? corner key (false) 3") (assert (= false (has-value? {false 8} 7)) "has-value? corner key (false) 3")
# contains-key? # has-key?
(do (do
(var test-contains-key-auto 0) (var test-has-key-auto 0)
(defn test-contains-key [col key expected &keys {:name name}] (defn test-has-key [col key expected &keys {:name name}]
``Test that contains-key has the outcome `expected`, and that if ``Test that has-key has the outcome `expected`, and that if
the result is true, then ensure (in key) does not fail either`` the result is true, then ensure (in key) does not fail either``
(assert (boolean? expected)) (assert (boolean? expected))
(default name (string "contains-key? " (++ test-contains-key-auto))) (default name (string "has-key? " (++ test-has-key-auto)))
(assert (= expected (contains-key? col key)) name) (assert (= expected (has-key? col key)) name)
(if (if
# guarenteed by `contains-key?` to never fail # guarenteed by `has-key?` to never fail
expected (in col key) expected (in col key)
# if `contains-key?` is false, then `in` should fail (for indexed types) # if `has-key?` is false, then `in` should fail (for indexed types)
# #
# For dictionary types, it should return nil # For dictionary types, it should return nil
(let [[success retval] (protect (in col key))] (let [[success retval] (protect (in col key))]
@ -81,26 +81,26 @@
"%s: expected (in col key) to %s, but got %q" "%s: expected (in col key) to %s, but got %q"
name (if expected "succeed" "fail") retval))))) name (if expected "succeed" "fail") retval)))))
(test-contains-key [] 0 false) # 1 (test-has-key [] 0 false) # 1
(test-contains-key [4 7 1 3] 2 true) # 2 (test-has-key [4 7 1 3] 2 true) # 2
(test-contains-key [4 7 1 3] 22 false) # 3 (test-has-key [4 7 1 3] 22 false) # 3
(test-contains-key @[1 2 3] 4 false) # 4 (test-has-key @[1 2 3] 4 false) # 4
(test-contains-key @[:a :b :c] 2 true) # 5 (test-has-key @[:a :b :c] 2 true) # 5
(test-contains-key {} :foo false) # 6 (test-has-key {} :foo false) # 6
(test-contains-key {:a :A :b :B} :a true) # 7 (test-has-key {:a :A :b :B} :a true) # 7
(test-contains-key {:a :A :b :B} :A false) # 8 (test-has-key {:a :A :b :B} :A false) # 8
(test-contains-key @{:a :A :b :B} :a true) # 9 (test-has-key @{:a :A :b :B} :a true) # 9
(test-contains-key "abc" 1 true) # 10 (test-has-key "abc" 1 true) # 10
(test-contains-key "abc" 4 false) # 11 (test-has-key "abc" 4 false) # 11
# weird true/false corner cases # weird true/false corner cases
# #
# Tries to mimic the corresponding corner cases in contains? and index-of, # Tries to mimic the corresponding corner cases in has-value? and index-of,
# but with keys/values inverted # but with keys/values inverted
# #
# in the first two cases (truthy? (get val col)) would have given false negatives # in the first two cases (truthy? (get val col)) would have given false negatives
(test-contains-key {7 true 8 false} 8 true :name "contains-key? corner value (false) 1") (test-has-key {7 true 8 false} 8 true :name "has-key? corner value (false) 1")
(test-contains-key @{8 false} 8 true :name "contains-key? corner value (false) 2") (test-has-key @{8 false} 8 true :name "has-key? corner value (false) 2")
(test-contains-key @{8 false} 7 false :name "contains-key? corner value (false) 3")) (test-has-key @{8 false} 7 false :name "has-key? corner value (false) 3"))
# Regression # Regression
(assert (= {:x 10} (|(let [x $] ~{:x ,x}) 10)) "issue 463") (assert (= {:x 10} (|(let [x $] ~{:x ,x}) 10)) "issue 463")