Почему привязка влияет на тип моей карты? - программирование

Почему привязка влияет на тип моей карты?

Я играл в REPL, и у меня было какое-то странное поведение:

Clojure 1.4.0
user=> (type {:a 1})
clojure.lang.PersistentArrayMap
user=> (def x {:a 1})
#'user/x
user=> (type x)
clojure.lang.PersistentHashMap

Я думал, что все маленькие буквенные карты являются экземплярами PersistentArrayMap, но, по-видимому, это не тот случай, если он связан с def. Почему использование def вызывает Clojure для выбора другого представления для моей карты litte? Я знаю, что это, вероятно, какая-то странная деталь реализации, но мне любопытно.

4b9b3361

Ответ 1

Этот вопрос заставлял меня копаться в исходном коде Clojure. Я просто потратил несколько часов на то, чтобы напечатать заявления в источнике, чтобы понять это.

Оказывается, два выражения карты оцениваются с помощью разных кодовых путей

(type {:a 1}) заставляет вызывать и запускать байт-код Java. Испускаемый код использует clojure.lang.RT.map() для построения карты, которая возвращает PersistentArrayMap для небольших карт:

static public IPersistentMap map(Object... init){
    if(init == null)
        return PersistentArrayMap.EMPTY;
    else if(init.length <= PersistentArrayMap.HASHTABLE_THRESHOLD)
        return PersistentArrayMap.createWithCheck(init);
    return PersistentHashMap.createWithCheck(init);
}

При оценке (def x {:a 1}) по крайней мере из REPL там не выдается байт-код. Постоянная карта анализируется как PersistentHashMap в clojure.lang.Compiler$MapExpr.parse(), которая возвращает ее в файл ConstantExpr:

else if(constant)
{
IPersistentMap m = PersistentHashMap.EMPTY;
for(int i=0;i<keyvals.length();i+= 2)
    {
    m = m.assoc(((LiteralExpr)keyvals.nth(i)).val(), ((LiteralExpr)keyvals.nth(i+1)).val());
    }
//System.err.println("Constant: " + m);
return new ConstantExpr(m);
}

Выражение def при оценке связывает значение созданного выше ConstantExpr, которое, как сказано, является PersistentHashMap.

Итак, почему это реализовано таким образом?

Я не знаю. Это может быть простой надзор или оптимизация PersistentArrayMap, возможно, не стоит того.