portal

mikejcusack 2024-04-04T23:39:58.739759Z

@djblue IntelliJ 2024.1 dropped so plugin needs an update πŸ™‚

djblue 2024-04-05T07:11:44.984569Z

Deployed https://github.com/djblue/portal/actions/runs/8566232685, now IntelliJ just needs to approve it

2
R.A. Porter 2024-04-05T00:27:09.868749Z

PR is up for you, Chris.

1
djblue 2024-04-05T06:50:04.550879Z

Will get this merged and released soon, thanks for the PR!

Alexander Kouznetsov 2024-04-04T02:45:36.739879Z

I’m experiencing a strange issue with portal. I tapped a data structure that has nested record-like objects. I then updated it recursively replacing record-like objects with plain clojure maps and tapped into portal. For some reason, it was still showing the record names on top of the objects even though I later figured that those were plain maps. Was there some sort of data indexing that might have gotten confused?

Alexander Kouznetsov 2024-04-05T15:53:20.651959Z

Good point, sounds like metadata is also going to be ignored when comparing nested objects, and also not shown correctly. I just verified it with this example (see the screenshot). So it looks like it is not very niche. See

(= (#'portal.runtime/value->key {:a (with-meta [1] {:one 1})})
   (#'portal.runtime/value->key {:a (with-meta [1] {:two 2})}))
true

(tap> {:a (with-meta [1] {:one 1})})
true
(tap> {:a (with-meta [1] {:two 2})})
true

Alexander Kouznetsov 2024-04-05T02:28:36.835989Z

I was able to reproduce this with basic clojure types. See the issue I filed: https://github.com/djblue/portal/issues/218.

djblue 2024-04-05T06:37:24.101869Z

Thanks for narrowing down this issue πŸ‘ So when Portal captures a value, it does take into consideration the metadata and type https://github.com/djblue/portal/blob/master/src/portal/runtime.cljc#L127-L131. However, I think the issue here is the parent map is also captured, which in a sense allows for bypassing the child check this check πŸ€”

djblue 2024-04-05T06:44:27.471909Z

So more specifically, this is the issue:

(= (value->key [1])      (value->key '(1)))      ; => false, which is good
(= (value->key {:a [1]}) (value->key {:a '(1)})) ; => true, which is bad

πŸ™Œ 1
djblue 2024-04-05T06:52:56.977859Z

Not sure how to solve this issue without Portal having its own notion of equality πŸ€”

Alexander Kouznetsov 2024-04-04T03:09:45.369119Z

Could it be using hashcode maybe or clojure equality?

Alexander Kouznetsov 2024-04-04T03:26:59.449399Z

I confirmed that if I first tap the plain maps object and then its original record-like, then nested structures of both will be shown as plain maps. If I do the opposite, tap record-like structure first and then plain map one - then nested structures for both are shown as record-like structures.

Alexander Kouznetsov 2024-04-04T03:32:12.552599Z

But if I do prn on each, I get clear picture that one object is made of plain maps and another from record-like structures.

Alexander Kouznetsov 2024-04-04T03:38:33.661509Z

Also if I select each and then do (-> user/p portal.api/selected prn) , I get the same value printed even though when I printed tap-list, it contained two different objects.

Alexander Kouznetsov 2024-04-04T04:08:29.891879Z

Interestingly, if I select both, printing them will show two different objects.

Alexander Kouznetsov 2024-04-04T04:09:39.309849Z

When I say record-like structure I refer to a Java object that implements some Clojure APIs, so it may be seen both as a map and as a record.

Alexander Kouznetsov 2024-04-04T04:12:43.534159Z

It implements

IObj, 
IMapIterable, 
IKVReduce, 
IRecord, 
Map<K, V>,
IPersistentMap,
MapEquivalence,
IHashEq,
IFn,
IMapIterable,
IKVReduce,
IObj
and extends AFn.

Alexander Kouznetsov 2024-04-04T04:52:48.935849Z

This behavior is only happening to objects that are stored in vectors. I. e. in {:v [{:a 1}]} , {:a 1} gets affected. While in {:p {:a 1}}, the same {:a 1} doesn’t get affected.

Alexander Kouznetsov 2024-04-17T18:38:16.817869Z

It takes a little while to come up with a test case here, but I’ll keep trying. Just maybe not as fast as I expected.

Alexander Kouznetsov 2024-04-16T18:40:25.052519Z

Nice, as I mentioned in the issue, my original case is still borken. I’m trying to come up with a test case. What I’m currently struggling with is to create an object that displays a type in the portal UI. What determines when a type is shown? For example, when I create the following object, its type is not shown in portal:

(def x (proxy [clojure.lang.APersistentMap clojure.lang.IRecord clojure.lang.IObj]
         []
         (toString [] "MyMap")
         (seq [] (clojure.lang.IteratorSeq/create (.iterator base)))
         (without [_] this)
         (meta [] {})
         (withMeta [_] this)
         (assoc [_ _] this)
         (assocEx [_ _] this)
         (iterator [] (.iterator base))
         (containsKey [_] false)
         (entryAt [_] nil)
         (count [] 1)
         (empty [] this)
         (valAt ([_] nil)
           ([_ _] nil))))
even though the type is something like user.proxy$clojure.lang.APersistentMap$IRecord$efc9b825

djblue 2024-04-16T19:02:05.509419Z

Currently only records show their type via https://github.com/djblue/portal/blob/master/src/portal/runtime.cljc#L262-L263

djblue 2024-04-16T19:02:45.217699Z

If the metadata include this key :portal.runtime/type , it will render it as the type

Alexander Kouznetsov 2024-04-16T19:58:34.148649Z

Thanks, this helps!

1
djblue 2024-04-06T23:13:38.515579Z

Ok, I think https://github.com/djblue/portal/commit/94171f4b9c1b2712871a19078288f793fa3fb17d fixes the issue πŸ‘Œ

πŸ™Œ 1