core-typed

2024-05-02T03:09:58.206919Z

Did t/Merge get removed from the library? I have tried using it from typed.clojure and from clojure.core.typed and in each case I am getting an error that it cannot resolve it. Specifically "Cannot resolve type: t/Merge"

2024-05-02T12:33:00.501469Z

I'm trying to use it inside of a defalias would that be why?

2024-05-02T14:33:02.400489Z

I'm also using macros like this for calls to pred as so. (defmacro mytype? [x] ((tyc/pred MyType) ~x))` I am doing it like that because I wanted to shorten those checks and if I do it as a def it doesn't seem to type check. Let me know if there is a better way to do that. Thanks

2024-05-02T15:36:47.624009Z

If you def it you need to annotate it (ann mypred (t/Pred MyType))

2024-05-02T15:37:25.249029Z

Could you show me how you're using t/Merge?

2024-05-02T16:21:45.047249Z

Oh ok that sounds great i'll try that instead of macros

2024-05-02T16:23:26.875359Z

BTW I forgot that I had integrated runtime checking with Malli. It doesn't cover all types, but it's another alternative to pred that the type checker understands https://github.com/typedclojure/typedclojure/blob/main/typed/malli/src/typed/malli.clj

2024-05-02T16:24:53.465399Z

it also can parse values (`conform` in spec). I think in the future I'll be fleshing out this integration.

2024-05-02T16:26:53.052359Z

Oh interesting I think I stumbled across that once. Whats the benefit of that vs just using pred?

2024-05-02T16:27:13.162209Z

Also, do you know the best way to supress the unresolved symbol errors kondo complains about when using pred in a def

2024-05-02T16:40:46.578739Z

Ik you can suppress it per form but I was wondering if you know of a way to do it globally for any calls to t/pred for instance

2024-05-02T16:50:48.844029Z

malli has more features like parse

(is (= [:int 1]
         (sut/parse (t/U ^{::sut/name :int} t/AnyInteger
                         ^{::sut/name :bool} t/Bool)
                    1)))
  (is (= [:bool true]
         (sut/parse (t/U ^{::sut/name :int} t/AnyInteger
                         ^{::sut/name :bool} t/Bool)
                    true))))

2024-05-02T16:52:27.923549Z

As for clj-kondo, try some things in this document. https://github.com/clj-kondo/clj-kondo/blob/master/doc/config.md#config-in-call perhaps: {:config-in-call {clojure.core.typed/pred {:ignore [:unresolved-symbol]}}}

2024-05-02T16:54:02.371179Z

That worked perfectly thanks

2024-05-02T16:54:05.978719Z

I'll think about how to add proper support for type aliases with clj-kondo. malli just spits out a static file that clj-kondo can consume, I might do that.

👍 1
2024-05-02T16:58:04.028209Z

looks like I forgot to add native clj-kondo support for pred, could you open an issue to remind me?

2024-05-02T17:00:26.020969Z

I'm trying to use t/Merge like so:

(t/defalias UserWithMore 
(t/Merge 
  User
  (t/HMap :mandatory                                                 {:extra-field1 t/Int                                           :extra-field2 t/Int}                                                                                    :complete? true)))

2024-05-02T17:01:15.244249Z

Then I get "Syntax error macroexpanding tyc/pred" in the pred function I made for that type. This is using the def as well not a macro for the pred

2024-05-02T18:08:48.687579Z

Could you paste the full stacktrace?

2024-05-02T18:10:45.581839Z

Start checking mynamespace
Syntax error macroexpanding tyc/pred at (file:myfile.clj:174:28).
Found errors
Subprocess failed (exit code: 1)

2024-05-02T18:10:58.198069Z

Thats really all it says

2024-05-02T18:58:30.141139Z

Ok, I'm guessing pred doesn't support Merge. This is probably one of those things that is easy to add support for in typed.malli but a pain for pred.

2024-05-02T19:00:54.273669Z

Hmm ok do you think I should try out the typed Malli approach? I would just use that validate function instead of pred right?

2024-05-02T19:36:14.964669Z

Not really, I think it has even less coverage at the moment. I'll experiment a bit and see if I can make it more useful.

2024-05-02T19:48:55.489039Z

Ok thanks I mean ideally I’d just use pred but if you think it’s too much to add merge support into it I am open to using something else in its place just let me know what you think would be my best option. And for now I’ll just not use merge yet.

2024-05-04T17:51:14.709109Z

Is there any other way I can let the type checker know that i'm returning a map of a certain type? Or is t/pred the standard way to do so?

2024-05-02T06:54:32.173559Z

(deftest Merge-test
  (is-tc-e nil (t/Merge))
  (is-tc-err {} (t/Merge))
  (is-tc-e {:a 1} (t/Merge '{:a t/Int}))
  (is-tc-err {:a :a} (t/Merge '{:a t/Int}))
  (is-tc-e {:a 1 :b true} (t/Merge '{:a t/Int} '{:b t/Bool}))
  (is-tc-err {:a 1 :b 1} (t/Merge '{:a t/Int} '{:b t/Bool}))
  (is-tc-e {:a true} (t/Merge '{:a t/Int} '{:a t/Bool}))
  (is-tc-err {:a 1} (t/Merge '{:a t/Int} '{:a t/Bool})))

2024-05-06T19:02:47.177159Z

@toddcampanellajr there's lots of ways. t/pred is just the safest, since it's backed by runtime checks.

2024-05-06T19:04:42.396029Z

you can use ^{::t/unsafe-cast T} E to cast the return value without checking

2024-05-06T19:05:02.347869Z

if postconditions are enough, you can use {:post [(something? %]}

2024-05-06T19:11:13.906459Z

Yeah I prefer t/pred vs those options but good to know about. Thanks.

2024-05-02T03:19:04.595839Z

Also, is there any way to do a generic Result type like in Rust? I know you can simulate a concrete Result Type like (t/U t/Int MyError) but I was wondering if theres any way to make a generic Result type or if its best to use a different approach.

2024-05-03T03:24:15.604629Z

you would use a tagged union in this case.

(defalias Result (TFn [x] (U '{:op ':Ok :result x} '{:op ':Err}))

2024-05-03T03:24:58.197259Z

then (case (:op m) :Ok .. :Err) would be the "elimination rules".

2024-08-01T11:29:41.992249Z

I'm trying this out now and I care about the error so I made the type like this. (t/defalias Result (t/TFn [x] (t/U '{:op ':Ok :result x} '{:op ':Err :error x}))) However, the type checker cannot resolve it for some reason when I construct it like {:op :Ok :result any-value} or {:op :Err :result any-error}. I get errors like:

Type mismatch:

Expected:       my-ns/Result

Actual:         (t/HMap :mandatory {:result nil, :op (t/Val :Ok)} :complete? true)


in:
{:op :Ok, :result (:message-id response)}
Type mismatch:

Expected:       my-ns/Result

Actual:         (t/HMap :mandatory {:op (t/Val :Err), :result String} :complete? true)


in:
{:op :Err, :result full-error}
Type mismatch:

Expected:       my-ns/Result

Actual:         (t/HMap :mandatory {:result t/Any, :op (t/Val :Ok)} :complete? true)


in:
{:op :Ok, :result result}
And my-ns/Result is just an alias over the result type like (t/defalias Result types/Result) just so its shorter. I normally make all my types using HMap and not the short form syntax so I think that is where some of the issues may be. Thanks for any help.

2024-08-01T11:34:43.073589Z

I also have never used t/TFn before so that may be part of the problem as well

2024-08-01T16:01:49.454149Z

Result here is a "type function", in this case a function that takes a type x and returns a union type.

2024-08-01T16:02:25.951619Z

similar to Seqable. You need to provide it a type with (Result Foo).

2024-08-01T16:03:31.921409Z

You probably want :error String not :error x

2024-08-01T17:29:31.843289Z

Ok cool i figured it was due to me not knowing fully how that works let me test some more

2024-05-03T13:56:20.880409Z

Ok cool I haven't explored that feature yet looks pretty useful though. How would I return an Ok variant or Err variant from a function? Essentially how do I construct one of those Result types

2024-05-03T14:53:05.806339Z

(defn my-fn []
  (try {:op :Ok :result 1}
       (catch Exception e {:op :Err :error e})))

2024-05-03T15:12:29.779639Z

Interesting i'll try this out