diff --git a/pykusto/expressions.py b/pykusto/expressions.py
index a02183b..ec73163 100644
--- a/pykusto/expressions.py
+++ b/pykusto/expressions.py
@@ -21,14 +21,6 @@ OrderType = Union[DatetimeType, TimespanType, NumberType, StringType]
 # All classes in the same file to prevent circular dependencies
 
 def _subexpr_to_kql(obj: ExpressionType) -> KQL:
-    """
-    Convert the given expression to KQL, enclosing it in parentheses if it is a compound expression. This guarantees
-    correct evaluation order. When parentheses are not needed, for example when the expressions is used as an argument
-    to a function, use `to_kql` instead.
-
-    :param obj: Expression to convert to KQL
-    :return: KQL that represents the given expression
-    """
     if isinstance(obj, BaseExpression):
         return obj.as_subexpression()
     return to_kql(obj)
@@ -42,11 +34,8 @@ class BaseExpression:
             raise TypeError("BaseExpression is abstract")
         return object.__new__(cls)
 
-    def __init__(self, kql: Union[KQL, 'BaseExpression']) -> None:
-        if isinstance(kql, BaseExpression):
-            self.kql = kql.kql
-        elif not isinstance(kql, str):
-            raise ValueError("Either expression or KQL required")
+    def __init__(self, kql: KQL) -> None:
+        assert isinstance(kql, str)
         self.kql = kql
 
     def __repr__(self) -> str:
@@ -270,9 +259,9 @@ class StringExpression(BaseExpression):
 
     def split(self, delimiter: StringType, requested_index: NumberType = None) -> 'ArrayExpression':
         if requested_index is None:
-            return ArrayExpression(KQL('split({}, {})'.format(to_kql(self.kql), to_kql(delimiter))))
-        return ArrayExpression(KQL('split({}, {}, {})'.format(
-            to_kql(self.kql), to_kql(delimiter), to_kql(requested_index)
+            return ArrayExpression(KQL('split({}, {}'.format(self.kql, to_kql(delimiter))))
+        return ArrayExpression(KQL('split({}, {}, {}'.format(
+            self.kql, _subexpr_to_kql(delimiter), to_kql(requested_index)
         )))
 
     def equals(self, other: StringType, case_sensitive: bool = False) -> BooleanExpression:
@@ -654,15 +643,6 @@ column_generator = ColumnGenerator()
 
 
 def to_kql(obj: ExpressionType) -> KQL:
-    """
-    Convert the given expression to KQL. If this is a subexpression of a greater expression, neighboring operators might
-    take precedence over operators included in this expression, causing an incorrect evaluation order.
-    If this is a concern, use `_subexpr_to_kql` instead, which will enclose this expression in parentheses if it is
-    a compound expression.
-
-    :param obj: Expression to convert to KQL
-    :return: KQL that represents the given expression
-    """
     if isinstance(obj, BaseExpression):
         return obj.kql
     return kql_converter.for_obj(obj)
diff --git a/pykusto/functions.py b/pykusto/functions.py
index 6269870..fcfc6f4 100644
--- a/pykusto/functions.py
+++ b/pykusto/functions.py
@@ -1,10 +1,10 @@
+import json
 from typing import Union
 
 from pykusto.expressions import Column, NumberType, NumberExpression, TimespanType, \
     DatetimeExpression, TimespanExpression, ArrayType, DynamicType, DatetimeType, BaseExpression, BooleanType, \
     ExpressionType, AggregationExpression, StringType, StringExpression, BooleanExpression, \
-    NumberAggregationExpression, MappingAggregationExpression, ArrayAggregationExpression, to_kql, DynamicExpression, \
-    ArrayExpression
+    NumberAggregationExpression, MappingAggregationExpression, ArrayAggregationExpression, to_kql, DynamicExpression
 from pykusto.kql_converters import KQL
 from pykusto.type_utils import plain_expression
 
@@ -559,8 +559,7 @@ def sign(expr: NumberType) -> NumberExpression:
 # def sin(self): return
 #
 #
-def split(string: StringType, delimiter: StringType, requested_index: NumberType = None) -> 'ArrayExpression':
-    return StringExpression(KQL(string)).split(delimiter, requested_index)
+# def split(self): return
 
 
 def sqrt(expr: NumberType) -> NumberExpression:
@@ -583,16 +582,20 @@ def startofyear(expr: DatetimeType, offset: NumberType = None) -> DatetimeExpres
     return expr.startofyear(offset)
 
 
-def strcat(expr1: StringType, expr2: StringType, *exprs: StringType) -> StringExpression:
-    res = 'strcat({}, {}'.format(to_kql(expr1),
-                                 to_kql(expr2))
-    if len(exprs) > 0:
-        res = res + ', ' + ', '.join([to_kql(expr) for expr in exprs])
-    return StringExpression(KQL(res + ')'))
+def strcat(*strings: StringType) -> StringExpression:
+    if len(strings) < 2:
+        raise ValueError("strcat requires at least two arguments")
+    return StringExpression(KQL('strcat({})'.format(', '.join(to_kql(s) for s in strings))))
+
+
+def to_literal_dynamic(d: DynamicType) -> KQL:
+    if isinstance(d, BaseExpression):
+        return d.kql
+    return KQL('dynamic({})'.format(json.dumps(d)))
 
 
 def strcat_array(expr: ArrayType, delimiter: StringType) -> StringExpression:
-    return StringExpression(KQL('strcat_array({}, {})'.format(to_kql(expr), to_kql(delimiter))))
+    return StringExpression(KQL('strcat_array({}, {})'.format(to_literal_dynamic(expr), to_kql(delimiter))))
 
 
 def strcat_delim(delimiter: StringType, expr1: StringType, expr2: StringType, *exprs: StringType) -> StringExpression:
diff --git a/pykusto/kql_converters.py b/pykusto/kql_converters.py
index 63079f4..a1eaeae 100644
--- a/pykusto/kql_converters.py
+++ b/pykusto/kql_converters.py
@@ -29,7 +29,7 @@ def timedelta_to_kql(td: timedelta) -> KQL:
 @kql_converter(Mapping, List, Tuple)
 def dynamic_to_kql(d: Union[Mapping, List, Tuple]) -> KQL:
     query = list(json.dumps(d))
-    # Issue #11
+    # Convert square brackets to round brackets (Issue #11)
     counter = 0
     prev = ""
     for i, c in enumerate(query):
diff --git a/pykusto/logger.py b/pykusto/logger.py
deleted file mode 100644
index 6b2cc66..0000000
--- a/pykusto/logger.py
+++ /dev/null
@@ -1,3 +0,0 @@
-import logging
-
-logger = logging.getLogger("pykusto")
diff --git a/pykusto/query.py b/pykusto/query.py
index 845517c..8207f13 100644
--- a/pykusto/query.py
+++ b/pykusto/query.py
@@ -1,18 +1,18 @@
-from abc import abstractmethod
-from copy import copy, deepcopy
-from enum import Enum
 from itertools import chain
-from types import FunctionType
 from typing import Tuple, List, Union, Optional
 
+from abc import abstractmethod
 from azure.kusto.data.helpers import dataframe_from_result_table
+from copy import copy, deepcopy
+from enum import Enum
+from types import FunctionType
 
 from pykusto.client import Table
 from pykusto.expressions import BooleanType, ExpressionType, AggregationExpression, OrderType, \
     StringType, AssignmentBase, AssignmentFromAggregationToColumn, AssignmentToSingleColumn, Column, BaseExpression, \
     AssignmentFromColumnToColumn, AnyExpression, to_kql
 from pykusto.kql_converters import KQL
-from pykusto.logger import logger
+from pykusto.type_utils import logger
 from pykusto.udf import stringify_python_func
 
 
diff --git a/pykusto/type_utils.py b/pykusto/type_utils.py
index ca407cd..bb5cb4d 100644
--- a/pykusto/type_utils.py
+++ b/pykusto/type_utils.py
@@ -1,65 +1,41 @@
+import logging
 from datetime import datetime, timedelta
 from numbers import Number
-from typing import Union, Mapping, Type, Dict, Callable, Tuple, List
+from typing import Union, Mapping, Type, Dict, Callable, Any, Tuple, List
+
+logger = logging.getLogger("pykusto")
 
 KustoTypes = Union[str, Number, bool, datetime, Mapping, List, Tuple, timedelta]
 # TODO: Unhandled data types: guid, decimal
 
 
 class TypeRegistrar:
-    """
-    A factory for annotations that are used to create a mapping between Kusto types and python types and functions.
-    Each annotation must be called with a Kusto type as a parameter. The `for_obj` and `for_type` methods
-    can then be used to retrieve the python type or function corresponding to a given Kusto type.
-    """
     registry: Dict[Type[KustoTypes], Callable]
 
-    def __init__(self, name: str) -> None:
-        """
-        :param name: Name is used for better logging and clearer errors
-        """
-        self.name = name
+    def __init__(self) -> None:
         self.registry = {}
 
-    def __repr__(self) -> str:
-        return self.name
-
     def __call__(self, *types: Type[KustoTypes]) -> Callable:
         def inner(wrapped):
             for t in types:
-                previous = self.registry.setdefault(t, wrapped)
-                if previous is not wrapped:
-                    raise TypeError("{}: type already registered: {}".format(self, t.__name__))
+                self.registry[t] = wrapped
             return wrapped
 
         return inner
 
-    def for_obj(self, obj: KustoTypes) -> Callable:
-        """
-        Given an object of Kusto type, retrieve the python type or function associated with the object's type, and call
-        it with the given object as a parameter
-
-        :param obj: An object of Kusto type
-        :return: Associated python object
-        """
+    def for_obj(self, obj: Any) -> Any:
         for registered_type, registered_callable in self.registry.items():
             if isinstance(obj, registered_type):
                 return registered_callable(obj)
-        raise ValueError("{}: no registered callable for object {} of type {}".format(self, obj, type(obj).__name__))
+        raise ValueError("No registered callable for object {} of type {}".format(obj, type(obj).__name__))
 
     def for_type(self, t: Type[KustoTypes]) -> Callable:
-        """
-        Given a Kusto type, retrieve the associated python type or function
-
-        :param t: A Kusto type
-        :return: Associated python object
-        """
         for registered_type, registered_callable in self.registry.items():
             if issubclass(t, registered_type):
                 return registered_callable
-        raise ValueError("{}: no registered callable for type {}".format(self, t.__name__))
+        raise ValueError("No registered callable for type {}".format(t.__name__))
 
 
-kql_converter = TypeRegistrar("KQL Converter")
-plain_expression = TypeRegistrar("Plain expression")
-aggregation_expression = TypeRegistrar("Aggregation expression")
+kql_converter = TypeRegistrar()
+plain_expression = TypeRegistrar()
+aggregation_expression = TypeRegistrar()
diff --git a/setup.py b/setup.py
index ca8f191..543081f 100644
--- a/setup.py
+++ b/setup.py
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
 
 setup(
     name='pykusto',
-    version='0.0.9',
+    version='0.0.7',
     packages=find_packages(exclude=['test']),
     url='https://github.com/Azure/pykusto',
     license='MIT License',

In some contexts a dynamic literal needs to be created with the "dynamic" keyword
For example, currently `strcat_array` fails because it requires:
`strcat_array(dynamic(["A", "B", "C"]), ",")`
while pykusto produces:
`strcat_array(("A", "B", "C"), ",")`
diff --git a/test/test_base.py b/test/test_base.py
index dde3185..6321ec8 100644
--- a/test/test_base.py
+++ b/test/test_base.py
@@ -3,7 +3,7 @@ import sys
 from typing import Callable
 from unittest import TestCase
 
-from pykusto.logger import logger
+from pykusto.type_utils import logger
 
 
 class TestBase(TestCase):
diff --git a/test/test_functions.py b/test/test_functions.py
index 3ce0a5c..65d0d07 100644
--- a/test/test_functions.py
+++ b/test/test_functions.py
@@ -1,5 +1,4 @@
 import datetime
-import unittest
 
 from pykusto import functions as f
 from pykusto.expressions import column_generator as col
@@ -372,7 +371,6 @@ class TestFunction(TestBase):
             Query().extend(f.strcat_delim('-', ',', col.foo)).render()
         )
 
-    @unittest.skip("Enabled after #40 is fixed")
     def test_strcat_array(self):
         self.assertEqual(
             " | where (strcat_array(foo, \",\")) == \"A,B,C\"",
@@ -425,20 +423,6 @@ class TestFunction(TestBase):
             Query().where(f.substring(col.foo, col.bar, 4) == 'ABC,ABC').render()
         )
 
-    def test_split(self):
-        self.assertEqual(
-            ' | extend foo = (split(bar, "_", 3))',
-            Query().extend(foo=f.split(col.bar, "_", 3)).render()
-        )
-        self.assertEqual(
-            ' | extend foo = (split(bar, "_")[3])',
-            Query().extend(foo=f.split(col.bar, "_")[3]).render()
-        )
-        self.assertEqual(
-            ' | extend foo = (split("1_2", "_")[3])',
-            Query().extend(foo=f.split("1_2", "_")[3]).render()
-        )
-
     def test_tobool(self):
         self.assertEqual(
             " | where tobool(foo)",
diff --git a/test/test_utils.py b/test/test_utils.py
index 2b2e7aa..fc774c4 100644
--- a/test/test_utils.py
+++ b/test/test_utils.py
@@ -1,81 +1,16 @@
 from pykusto.expressions import to_kql
-from pykusto.type_utils import TypeRegistrar
 from test.test_base import TestBase
 
 
 class TestUtils(TestBase):
     def test_dynamic_to_kql(self):
-        test_dict = {
+        dict ={
             "name": "Alan",
             "age": 21,
             "address": ("NY", 36),
             "pets": ["Libby", "Panda", "]", "["]
         }
         self.assertEqual(
-            "{\"name\": \"Alan\", \"age\": 21, \"address\": (\"NY\", 36), "
-            "\"pets\": (\"Libby\", \"Panda\", \"]\", \"[\")}",
-            to_kql(test_dict)
-        )
-
-    def test_type_registrar_for_type(self):
-        test_annotation = TypeRegistrar("Test annotation")
-
-        @test_annotation(str)
-        def str_annotated(s: str) -> str:
-            return "response to " + s
-
-        self.assertEqual(
-            "response to test for_type",
-            test_annotation.for_type(str)("test for_type")
-        )
-
-    def test_type_registrar_for_obj(self):
-        test_annotation = TypeRegistrar("Test annotation")
-
-        @test_annotation(str)
-        def str_annotated(s: str) -> str:
-            return "response to " + s
-
-        self.assertEqual(
-            "response to test for_obj",
-            test_annotation.for_obj("test for_obj")
-        )
-
-    def test_type_registrar_for_type_not_found(self):
-        test_annotation = TypeRegistrar("Test annotation")
-
-        @test_annotation(str)
-        def str_annotated(s: str) -> str:
-            return "response to " + s
-
-        self.assertRaises(
-            ValueError("Test annotation: no registered callable for type bool"),
-            lambda: test_annotation.for_type(bool)("test for_type")
-        )
-
-    def test_type_registrar_for_obj_not_found(self):
-        test_annotation = TypeRegistrar("Test annotation")
-
-        @test_annotation(str)
-        def str_annotated(s: str) -> str:
-            return "response to " + s
-
-        self.assertRaises(
-            ValueError("Test annotation: no registered callable for object True of type bool"),
-            lambda: test_annotation.for_obj(True)
-        )
-
-    def test_type_registrar_collision(self):
-        test_annotation = TypeRegistrar("Test annotation")
-
-        @test_annotation(str)
-        def str_annotated_1(s: str) -> str:
-            return "response to " + s
-
-        def str_annotated_2(s: str) -> str:
-            return "response to " + s
-
-        self.assertRaises(
-            TypeError("Test annotation: type already registered: str"),
-            lambda: test_annotation(str)(str_annotated_2)
+            "{\"name\": \"Alan\", \"age\": 21, \"address\": (\"NY\", 36), \"pets\": (\"Libby\", \"Panda\", \"]\", \"[\")}",
+            to_kql(dict)
         )

pip install -e .
parse_log_pytest
requirements.txt
pytest
3.7
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
adal==1.2.7
azure-kusto-data==0.0.36
certifi @ file:///croot/certifi_1671487769961/work/certifi
cffi==1.15.1
charset-normalizer==3.4.1
cryptography==44.0.2
exceptiongroup==1.2.2
idna==3.10
importlib-metadata==6.7.0
iniconfig==2.0.0
packaging==24.0
pluggy==1.2.0
pycparser==2.21
PyJWT==2.8.0
-e git+https://github.com/Azure/pykusto.git@8783b166ce0ee3236ad6fcda81d9355a80438cd2#egg=pykusto
pytest==7.4.4
python-dateutil==2.9.0.post0
requests==2.31.0
six==1.17.0
tomli==2.0.1
typing_extensions==4.7.1
urllib3==2.0.7
zipp==3.15.0

name: pykusto
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2022.12.7=py37h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=22.3.1=py37h06a4308_0
  - python=3.7.16=h7a1cb2a_0
  - readline=8.2=h5eee18b_0
  - setuptools=65.6.3=py37h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.38.4=py37h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - adal==1.2.7
      - azure-kusto-data==0.0.36
      - cffi==1.15.1
      - charset-normalizer==3.4.1
      - cryptography==44.0.2
      - exceptiongroup==1.2.2
      - idna==3.10
      - importlib-metadata==6.7.0
      - iniconfig==2.0.0
      - packaging==24.0
      - pluggy==1.2.0
      - pycparser==2.21
      - pyjwt==2.8.0
      - pytest==7.4.4
      - python-dateutil==2.9.0.post0
      - requests==2.31.0
      - six==1.17.0
      - tomli==2.0.1
      - typing-extensions==4.7.1
      - urllib3==2.0.7
      - zipp==3.15.0
prefix: /opt/conda/envs/pykusto

test/test_functions.py::TestFunction::test_acos test/test_functions.py::TestFunction::test_ago test/test_functions.py::TestFunction::test_any test/test_functions.py::TestFunction::test_arg_max test/test_functions.py::TestFunction::test_arg_min test/test_functions.py::TestFunction::test_array_length test/test_functions.py::TestFunction::test_avg test/test_functions.py::TestFunction::test_avgif test/test_functions.py::TestFunction::test_bag_keys test/test_functions.py::TestFunction::test_bin test/test_functions.py::TestFunction::test_bin_at test/test_functions.py::TestFunction::test_bin_auto test/test_functions.py::TestFunction::test_case test/test_functions.py::TestFunction::test_ceiling test/test_functions.py::TestFunction::test_cos test/test_functions.py::TestFunction::test_count test/test_functions.py::TestFunction::test_countif test/test_functions.py::TestFunction::test_dcount test/test_functions.py::TestFunction::test_endofday test/test_functions.py::TestFunction::test_endofmonth test/test_functions.py::TestFunction::test_endofweek test/test_functions.py::TestFunction::test_exp test/test_functions.py::TestFunction::test_exp10 test/test_functions.py::TestFunction::test_exp2 test/test_functions.py::TestFunction::test_floor test/test_functions.py::TestFunction::test_format_datetime test/test_functions.py::TestFunction::test_format_timespan test/test_functions.py::TestFunction::test_getmonth test/test_functions.py::TestFunction::test_gettype test/test_functions.py::TestFunction::test_getyear test/test_functions.py::TestFunction::test_hash test/test_functions.py::TestFunction::test_hash_sha256 test/test_functions.py::TestFunction::test_hourofday test/test_functions.py::TestFunction::test_iff test/test_functions.py::TestFunction::test_iif test/test_functions.py::TestFunction::test_isempty test/test_functions.py::TestFunction::test_isfinite test/test_functions.py::TestFunction::test_isinf test/test_functions.py::TestFunction::test_isnan test/test_functions.py::TestFunction::test_isnotempty test/test_functions.py::TestFunction::test_isnotnull test/test_functions.py::TestFunction::test_isnull test/test_functions.py::TestFunction::test_isutf8 test/test_functions.py::TestFunction::test_log test/test_functions.py::TestFunction::test_log10 test/test_functions.py::TestFunction::test_log2 test/test_functions.py::TestFunction::test_loggamma test/test_functions.py::TestFunction::test_make_bag test/test_functions.py::TestFunction::test_make_datetime test/test_functions.py::TestFunction::test_make_list test/test_functions.py::TestFunction::test_make_set test/test_functions.py::TestFunction::test_max test/test_functions.py::TestFunction::test_min test/test_functions.py::TestFunction::test_nesting test/test_functions.py::TestFunction::test_now test/test_functions.py::TestFunction::test_parse_json_array test/test_functions.py::TestFunction::test_parse_json_brackets test/test_functions.py::TestFunction::test_parse_json_dot test/test_functions.py::TestFunction::test_parse_json_nesting test/test_functions.py::TestFunction::test_parse_json_number_expression test/test_functions.py::TestFunction::test_parse_json_to_string test/test_functions.py::TestFunction::test_percentile test/test_functions.py::TestFunction::test_percentiles test/test_functions.py::TestFunction::test_pow test/test_functions.py::TestFunction::test_round test/test_functions.py::TestFunction::test_sign test/test_functions.py::TestFunction::test_sqrt test/test_functions.py::TestFunction::test_startofday test/test_functions.py::TestFunction::test_startofmonth test/test_functions.py::TestFunction::test_startofweek test/test_functions.py::TestFunction::test_startofyear test/test_functions.py::TestFunction::test_stdev test/test_functions.py::TestFunction::test_stdevif test/test_functions.py::TestFunction::test_stdevp test/test_functions.py::TestFunction::test_strcat test/test_functions.py::TestFunction::test_strcat_array test/test_functions.py::TestFunction::test_strcat_delim test/test_functions.py::TestFunction::test_strcmp test/test_functions.py::TestFunction::test_string_size test/test_functions.py::TestFunction::test_strlen test/test_functions.py::TestFunction::test_strrep test/test_functions.py::TestFunction::test_substring test/test_functions.py::TestFunction::test_sum test/test_functions.py::TestFunction::test_sumif test/test_functions.py::TestFunction::test_tobool test/test_functions.py::TestFunction::test_toboolean test/test_functions.py::TestFunction::test_todouble test/test_functions.py::TestFunction::test_variance test/test_functions.py::TestFunction::test_varianceif test/test_functions.py::TestFunction::test_variancep test/test_utils.py::TestUtils::test_dynamic_to_kql
setup.py pykusto/functions.py pykusto/kql_converters.py pykusto/logger.py pykusto/query.py pykusto/expressions.py pykusto/type_utils.py
setup.py pykusto/functions.py pykusto/kql_converters.py pykusto/logger.py pykusto/query.py pykusto/expressions.py pykusto/type_utils.py