You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by pa...@apache.org on 2022/12/06 14:56:11 UTC

[arrow-nanoarrow] branch main updated: [C] Adapt ArrowSchema initialization to better support recursive types (#81)

This is an automated email from the ASF dual-hosted git repository.

paleolimbot pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-nanoarrow.git


The following commit(s) were added to refs/heads/main by this push:
     new db11c16  [C] Adapt ArrowSchema initialization to better support recursive types (#81)
db11c16 is described below

commit db11c168ecab99ecac9028afbf71427c7107bb12
Author: Dewey Dunnington <de...@fishandwhistle.net>
AuthorDate: Tue Dec 6 10:56:03 2022 -0400

    [C] Adapt ArrowSchema initialization to better support recursive types (#81)
    
    * start to separate Init from SetType
    
    * ArrowSchemaInit -> ArrowSchemaInitType
    
    * split out ArrowSchemaInit
    
    * split out fixed-size type setter
    
    * split out SetType for parameterized types
    
    * split out SetType and use it
    
    * allocate children for lists and maps
    
    * InitType -> InitFromType
    
    * ArrowArrayInit -> ArrowArrayInitFromType
    
    * fix bad search/replace
    
    * ArrayViewInit -> ArrayViewInitFromType
    
    * Document API changes
    
    * fix symbol, stub union
    
    * fix symbol
    
    * implement ArrowSchemaSetTypeUnion
    
    * allow zero-case union
    
    * test union output against Arrow C++; add struct creator
---
 examples/cmake-minimal/src/library.c    |   4 +-
 examples/vendored-minimal/src/library.c |   4 +-
 r/src/array_view.c                      |   2 +-
 r/src/convert.c                         |   2 +-
 src/nanoarrow/array.c                   |  28 ++--
 src/nanoarrow/array_inline.h            |   2 +-
 src/nanoarrow/array_stream_test.cc      |  16 +--
 src/nanoarrow/array_test.cc             | 170 +++++++++++------------
 src/nanoarrow/nanoarrow.h               | 135 ++++++++++++------
 src/nanoarrow/nanoarrow.hpp             |   2 +-
 src/nanoarrow/nanoarrow_hpp_test.cc     |  16 +--
 src/nanoarrow/schema.c                  | 168 +++++++++++++++-------
 src/nanoarrow/schema_test.cc            | 237 ++++++++++++++++++++------------
 13 files changed, 482 insertions(+), 304 deletions(-)

diff --git a/examples/cmake-minimal/src/library.c b/examples/cmake-minimal/src/library.c
index 9639f1a..b44f9ec 100644
--- a/examples/cmake-minimal/src/library.c
+++ b/examples/cmake-minimal/src/library.c
@@ -33,7 +33,7 @@ int make_simple_array(struct ArrowArray* array_out, struct ArrowSchema* schema_o
   array_out->release = NULL;
   schema_out->release = NULL;
 
-  NANOARROW_RETURN_NOT_OK(ArrowArrayInit(array_out, NANOARROW_TYPE_INT32));
+  NANOARROW_RETURN_NOT_OK(ArrowArrayInitFromType(array_out, NANOARROW_TYPE_INT32));
 
   NANOARROW_RETURN_NOT_OK(ArrowArrayStartAppending(array_out));
   NANOARROW_RETURN_NOT_OK(ArrowArrayAppendInt(array_out, 1));
@@ -41,7 +41,7 @@ int make_simple_array(struct ArrowArray* array_out, struct ArrowSchema* schema_o
   NANOARROW_RETURN_NOT_OK(ArrowArrayAppendInt(array_out, 3));
   NANOARROW_RETURN_NOT_OK(ArrowArrayFinishBuilding(array_out, &global_error));
   
-  NANOARROW_RETURN_NOT_OK(ArrowSchemaInit(schema_out, NANOARROW_TYPE_INT32));
+  NANOARROW_RETURN_NOT_OK(ArrowSchemaInitFromType(schema_out, NANOARROW_TYPE_INT32));
 
   return NANOARROW_OK;
 }
diff --git a/examples/vendored-minimal/src/library.c b/examples/vendored-minimal/src/library.c
index 07ef6ab..c1e634f 100644
--- a/examples/vendored-minimal/src/library.c
+++ b/examples/vendored-minimal/src/library.c
@@ -33,7 +33,7 @@ int make_simple_array(struct ArrowArray* array_out, struct ArrowSchema* schema_o
   array_out->release = NULL;
   schema_out->release = NULL;
 
-  NANOARROW_RETURN_NOT_OK(ArrowArrayInit(array_out, NANOARROW_TYPE_INT32));
+  NANOARROW_RETURN_NOT_OK(ArrowArrayInitFromType(array_out, NANOARROW_TYPE_INT32));
 
   NANOARROW_RETURN_NOT_OK(ArrowArrayStartAppending(array_out));
   NANOARROW_RETURN_NOT_OK(ArrowArrayAppendInt(array_out, 1));
@@ -41,7 +41,7 @@ int make_simple_array(struct ArrowArray* array_out, struct ArrowSchema* schema_o
   NANOARROW_RETURN_NOT_OK(ArrowArrayAppendInt(array_out, 3));
   NANOARROW_RETURN_NOT_OK(ArrowArrayFinishBuilding(array_out, &global_error));
 
-  NANOARROW_RETURN_NOT_OK(ArrowSchemaInit(schema_out, NANOARROW_TYPE_INT32));
+  NANOARROW_RETURN_NOT_OK(ArrowSchemaInitFromType(schema_out, NANOARROW_TYPE_INT32));
 
   return NANOARROW_OK;
 }
diff --git a/r/src/array_view.c b/r/src/array_view.c
index f34d97d..38b6a72 100644
--- a/r/src/array_view.c
+++ b/r/src/array_view.c
@@ -43,7 +43,7 @@ SEXP nanoarrow_c_array_view(SEXP array_xptr, SEXP schema_xptr) {
 
   struct ArrowArrayView* array_view =
       (struct ArrowArrayView*)ArrowMalloc(sizeof(struct ArrowArrayView));
-  ArrowArrayViewInit(array_view, NANOARROW_TYPE_UNINITIALIZED);
+  ArrowArrayViewInitFromType(array_view, NANOARROW_TYPE_UNINITIALIZED);
   SEXP xptr = PROTECT(R_MakeExternalPtr(array_view, R_NilValue, array_xptr));
   R_RegisterCFinalizer(xptr, &finalize_array_view_xptr);
 
diff --git a/r/src/convert.c b/r/src/convert.c
index be262ee..b3891b8 100644
--- a/r/src/convert.c
+++ b/r/src/convert.c
@@ -71,7 +71,7 @@ SEXP nanoarrow_converter_from_type(enum VectorType vector_type) {
       PROTECT(R_MakeExternalPtr(converter, R_NilValue, converter_shelter));
   R_RegisterCFinalizer(converter_xptr, &finalize_converter);
 
-  ArrowArrayViewInit(&converter->array_view, NANOARROW_TYPE_UNINITIALIZED);
+  ArrowArrayViewInitFromType(&converter->array_view, NANOARROW_TYPE_UNINITIALIZED);
   converter->schema_view.data_type = NANOARROW_TYPE_UNINITIALIZED;
   converter->schema_view.storage_data_type = NANOARROW_TYPE_UNINITIALIZED;
   converter->src.array_view = &converter->array_view;
diff --git a/src/nanoarrow/array.c b/src/nanoarrow/array.c
index 3cbfdd4..ae97597 100644
--- a/src/nanoarrow/array.c
+++ b/src/nanoarrow/array.c
@@ -122,7 +122,8 @@ static ArrowErrorCode ArrowArraySetStorageType(struct ArrowArray* array,
   return NANOARROW_OK;
 }
 
-ArrowErrorCode ArrowArrayInit(struct ArrowArray* array, enum ArrowType storage_type) {
+ArrowErrorCode ArrowArrayInitFromType(struct ArrowArray* array,
+                                      enum ArrowType storage_type) {
   array->length = 0;
   array->null_count = 0;
   array->offset = 0;
@@ -161,10 +162,10 @@ ArrowErrorCode ArrowArrayInit(struct ArrowArray* array, enum ArrowType storage_t
   return NANOARROW_OK;
 }
 
-static ArrowErrorCode ArrowArrayInitFromArrayView(struct ArrowArray* array,
-                                                  struct ArrowArrayView* array_view,
-                                                  struct ArrowError* error) {
-  ArrowArrayInit(array, array_view->storage_type);
+static ArrowErrorCode ArrowArrayInitFromTypeFromArrayView(
+    struct ArrowArray* array, struct ArrowArrayView* array_view,
+    struct ArrowError* error) {
+  ArrowArrayInitFromType(array, array_view->storage_type);
   struct ArrowArrayPrivateData* private_data =
       (struct ArrowArrayPrivateData*)array->private_data;
 
@@ -177,8 +178,8 @@ static ArrowErrorCode ArrowArrayInitFromArrayView(struct ArrowArray* array,
   private_data->layout = array_view->layout;
 
   for (int64_t i = 0; i < array_view->n_children; i++) {
-    int result =
-        ArrowArrayInitFromArrayView(array->children[i], array_view->children[i], error);
+    int result = ArrowArrayInitFromTypeFromArrayView(array->children[i],
+                                                     array_view->children[i], error);
     if (result != NANOARROW_OK) {
       array->release(array);
       return result;
@@ -193,7 +194,7 @@ ArrowErrorCode ArrowArrayInitFromSchema(struct ArrowArray* array,
                                         struct ArrowError* error) {
   struct ArrowArrayView array_view;
   NANOARROW_RETURN_NOT_OK(ArrowArrayViewInitFromSchema(&array_view, schema, error));
-  NANOARROW_RETURN_NOT_OK(ArrowArrayInitFromArrayView(array, &array_view, error));
+  NANOARROW_RETURN_NOT_OK(ArrowArrayInitFromTypeFromArrayView(array, &array_view, error));
   ArrowArrayViewReset(&array_view);
   return NANOARROW_OK;
 }
@@ -280,7 +281,7 @@ static ArrowErrorCode ArrowArrayViewInitFromArray(struct ArrowArrayView* array_v
   struct ArrowArrayPrivateData* private_data =
       (struct ArrowArrayPrivateData*)array->private_data;
 
-  ArrowArrayViewInit(array_view, private_data->storage_type);
+  ArrowArrayViewInitFromType(array_view, private_data->storage_type);
   array_view->layout = private_data->layout;
   array_view->array = array;
 
@@ -454,7 +455,8 @@ ArrowErrorCode ArrowArrayFinishBuilding(struct ArrowArray* array,
   return result;
 }
 
-void ArrowArrayViewInit(struct ArrowArrayView* array_view, enum ArrowType storage_type) {
+void ArrowArrayViewInitFromType(struct ArrowArrayView* array_view,
+                                enum ArrowType storage_type) {
   memset(array_view, 0, sizeof(struct ArrowArrayView));
   array_view->storage_type = storage_type;
   ArrowLayoutInit(&array_view->layout, storage_type);
@@ -484,7 +486,7 @@ ArrowErrorCode ArrowArrayViewAllocateChildren(struct ArrowArrayView* array_view,
     if (array_view->children[i] == NULL) {
       return ENOMEM;
     }
-    ArrowArrayViewInit(array_view->children[i], NANOARROW_TYPE_UNINITIALIZED);
+    ArrowArrayViewInitFromType(array_view->children[i], NANOARROW_TYPE_UNINITIALIZED);
   }
 
   return NANOARROW_OK;
@@ -499,7 +501,7 @@ ArrowErrorCode ArrowArrayViewInitFromSchema(struct ArrowArrayView* array_view,
     return result;
   }
 
-  ArrowArrayViewInit(array_view, schema_view.storage_data_type);
+  ArrowArrayViewInitFromType(array_view, schema_view.storage_data_type);
   array_view->layout = schema_view.layout;
 
   result = ArrowArrayViewAllocateChildren(array_view, schema->n_children);
@@ -532,7 +534,7 @@ void ArrowArrayViewReset(struct ArrowArrayView* array_view) {
     ArrowFree(array_view->children);
   }
 
-  ArrowArrayViewInit(array_view, NANOARROW_TYPE_UNINITIALIZED);
+  ArrowArrayViewInitFromType(array_view, NANOARROW_TYPE_UNINITIALIZED);
 }
 
 void ArrowArrayViewSetLength(struct ArrowArrayView* array_view, int64_t length) {
diff --git a/src/nanoarrow/array_inline.h b/src/nanoarrow/array_inline.h
index d020a2b..7e7a34b 100644
--- a/src/nanoarrow/array_inline.h
+++ b/src/nanoarrow/array_inline.h
@@ -443,7 +443,7 @@ static inline ArrowErrorCode ArrowArrayFinishElement(struct ArrowArray* array) {
 static inline void ArrowArrayViewMove(struct ArrowArrayView* src,
                                       struct ArrowArrayView* dst) {
   memcpy(dst, src, sizeof(struct ArrowArrayView));
-  ArrowArrayViewInit(src, NANOARROW_TYPE_UNINITIALIZED);
+  ArrowArrayViewInitFromType(src, NANOARROW_TYPE_UNINITIALIZED);
 }
 
 static inline int8_t ArrowArrayViewIsNull(struct ArrowArrayView* array_view, int64_t i) {
diff --git a/src/nanoarrow/array_stream_test.cc b/src/nanoarrow/array_stream_test.cc
index 26d49ad..efb39dc 100644
--- a/src/nanoarrow/array_stream_test.cc
+++ b/src/nanoarrow/array_stream_test.cc
@@ -24,11 +24,11 @@ TEST(ArrayStreamTest, ArrayStreamTestBasic) {
   struct ArrowArray array;
   struct ArrowSchema schema;
 
-  ASSERT_EQ(ArrowSchemaInit(&schema, NANOARROW_TYPE_INT32), NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_INT32), NANOARROW_OK);
   EXPECT_EQ(ArrowBasicArrayStreamInit(&array_stream, &schema, 1), NANOARROW_OK);
   EXPECT_EQ(schema.release, nullptr);
 
-  ASSERT_EQ(ArrowArrayInit(&array, NANOARROW_TYPE_INT32), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_INT32), NANOARROW_OK);
   ASSERT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
   ASSERT_EQ(ArrowArrayAppendInt(&array, 123), NANOARROW_OK);
   ASSERT_EQ(ArrowArrayFinishBuilding(&array, nullptr), NANOARROW_OK);
@@ -63,10 +63,10 @@ TEST(ArrayStreamTest, ArrayStreamTestEmpty) {
   struct ArrowArray array;
   struct ArrowSchema schema;
 
-  ASSERT_EQ(ArrowSchemaInit(&schema, NANOARROW_TYPE_INT32), NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_INT32), NANOARROW_OK);
   EXPECT_EQ(ArrowBasicArrayStreamInit(&array_stream, &schema, 0), NANOARROW_OK);
   EXPECT_EQ(ArrowBasicArrayStreamValidate(&array_stream, nullptr), NANOARROW_OK);
-  
+
   for (int i = 0; i < 5; i++) {
     EXPECT_EQ(array_stream.get_next(&array_stream, &array), NANOARROW_OK);
     EXPECT_EQ(array.release, nullptr);
@@ -80,12 +80,12 @@ TEST(ArrayStreamTest, ArrayStreamTestIncomplete) {
   struct ArrowArray array;
   struct ArrowSchema schema;
 
-  ASSERT_EQ(ArrowSchemaInit(&schema, NANOARROW_TYPE_INT32), NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_INT32), NANOARROW_OK);
   ASSERT_EQ(ArrowBasicArrayStreamInit(&array_stream, &schema, 5), NANOARROW_OK);
 
   // Add five arrays with length == i
   for (int i = 0; i < 5; i++) {
-    ASSERT_EQ(ArrowArrayInit(&array, NANOARROW_TYPE_INT32), NANOARROW_OK);
+    ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_INT32), NANOARROW_OK);
     ASSERT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
     for (int j = 0; j < i; j++) {
       ASSERT_EQ(ArrowArrayAppendInt(&array, 123), NANOARROW_OK);
@@ -109,10 +109,10 @@ TEST(ArrayStreamTest, ArrayStreamTestInvalid) {
   struct ArrowSchema schema;
   struct ArrowError error;
 
-  ASSERT_EQ(ArrowSchemaInit(&schema, NANOARROW_TYPE_INT32), NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_INT32), NANOARROW_OK);
   ASSERT_EQ(ArrowBasicArrayStreamInit(&array_stream, &schema, 1), NANOARROW_OK);
 
-  ASSERT_EQ(ArrowArrayInit(&array, NANOARROW_TYPE_STRING), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_STRING), NANOARROW_OK);
   ASSERT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
   ASSERT_EQ(ArrowArrayFinishBuilding(&array, nullptr), NANOARROW_OK);
   ArrowBasicArrayStreamSetArray(&array_stream, 0, &array);
diff --git a/src/nanoarrow/array_test.cc b/src/nanoarrow/array_test.cc
index 9ab3b9c..ac9ca0d 100644
--- a/src/nanoarrow/array_test.cc
+++ b/src/nanoarrow/array_test.cc
@@ -47,48 +47,50 @@ void ARROW_EXPECT_OK(Result<std::shared_ptr<Array>> result) {
 TEST(ArrayTest, ArrayTestInit) {
   struct ArrowArray array;
 
-  EXPECT_EQ(ArrowArrayInit(&array, NANOARROW_TYPE_UNINITIALIZED), NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_UNINITIALIZED), NANOARROW_OK);
   EXPECT_EQ(array.n_buffers, 0);
   array.release(&array);
 
-  EXPECT_EQ(ArrowArrayInit(&array, NANOARROW_TYPE_STRUCT), NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_STRUCT), NANOARROW_OK);
   EXPECT_EQ(array.n_buffers, 1);
   array.release(&array);
 
-  EXPECT_EQ(ArrowArrayInit(&array, NANOARROW_TYPE_INT32), NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_INT32), NANOARROW_OK);
   EXPECT_EQ(array.n_buffers, 2);
   array.release(&array);
 
-  EXPECT_EQ(ArrowArrayInit(&array, NANOARROW_TYPE_STRING), NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_STRING), NANOARROW_OK);
   EXPECT_EQ(array.n_buffers, 3);
   array.release(&array);
 
-  EXPECT_EQ(ArrowArrayInit(&array, NANOARROW_TYPE_DATE64), EINVAL);
+  EXPECT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_DATE64), EINVAL);
 }
 
 TEST(ArrayTest, ArrayTestAllocateChildren) {
   struct ArrowArray array;
 
-  ASSERT_EQ(ArrowArrayInit(&array, NANOARROW_TYPE_STRUCT), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_STRUCT), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAllocateChildren(&array, 0), NANOARROW_OK);
   EXPECT_EQ(array.n_children, 0);
   array.release(&array);
 
-  ASSERT_EQ(ArrowArrayInit(&array, NANOARROW_TYPE_STRUCT), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_STRUCT), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAllocateChildren(
                 &array, std::numeric_limits<int64_t>::max() / sizeof(void*)),
             ENOMEM);
   array.release(&array);
 
-  ASSERT_EQ(ArrowArrayInit(&array, NANOARROW_TYPE_STRUCT), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_STRUCT), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAllocateChildren(&array, 2), NANOARROW_OK);
   EXPECT_EQ(array.n_children, 2);
   ASSERT_NE(array.children, nullptr);
   ASSERT_NE(array.children[0], nullptr);
   ASSERT_NE(array.children[1], nullptr);
 
-  ASSERT_EQ(ArrowArrayInit(array.children[0], NANOARROW_TYPE_INT32), NANOARROW_OK);
-  ASSERT_EQ(ArrowArrayInit(array.children[1], NANOARROW_TYPE_STRING), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayInitFromType(array.children[0], NANOARROW_TYPE_INT32),
+            NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayInitFromType(array.children[1], NANOARROW_TYPE_STRING),
+            NANOARROW_OK);
 
   EXPECT_EQ(ArrowArrayAllocateChildren(&array, 0), EINVAL);
 
@@ -98,11 +100,12 @@ TEST(ArrayTest, ArrayTestAllocateChildren) {
 TEST(ArrayTest, ArrayTestAllocateDictionary) {
   struct ArrowArray array;
 
-  ASSERT_EQ(ArrowArrayInit(&array, NANOARROW_TYPE_STRUCT), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_STRUCT), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAllocateDictionary(&array), NANOARROW_OK);
   ASSERT_NE(array.dictionary, nullptr);
 
-  ASSERT_EQ(ArrowArrayInit(array.dictionary, NANOARROW_TYPE_STRING), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayInitFromType(array.dictionary, NANOARROW_TYPE_STRING),
+            NANOARROW_OK);
 
   EXPECT_EQ(ArrowArrayAllocateDictionary(&array), EINVAL);
 
@@ -114,10 +117,12 @@ TEST(ArrayTest, ArrayTestInitFromSchema) {
   struct ArrowSchema schema;
   struct ArrowError error;
 
-  ASSERT_EQ(ArrowSchemaInit(&schema, NANOARROW_TYPE_STRUCT), NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_STRUCT), NANOARROW_OK);
   ASSERT_EQ(ArrowSchemaAllocateChildren(&schema, 2), NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaInit(schema.children[0], NANOARROW_TYPE_INT32), NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaInit(schema.children[1], NANOARROW_TYPE_STRING), NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaInitFromType(schema.children[0], NANOARROW_TYPE_INT32),
+            NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaInitFromType(schema.children[1], NANOARROW_TYPE_STRING),
+            NANOARROW_OK);
 
   EXPECT_EQ(ArrowArrayInitFromSchema(&array, &schema, &error), NANOARROW_OK);
   EXPECT_EQ(array.n_children, 2);
@@ -134,7 +139,7 @@ TEST(ArrayTest, ArrayTestSetBitmap) {
   ArrowBitmapAppend(&bitmap, true, 9);
 
   struct ArrowArray array;
-  ASSERT_EQ(ArrowArrayInit(&array, NANOARROW_TYPE_INT32), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_INT32), NANOARROW_OK);
   ArrowArraySetValidityBitmap(&array, &bitmap);
   EXPECT_EQ(bitmap.buffer.data, nullptr);
   const uint8_t* bitmap_buffer = reinterpret_cast<const uint8_t*>(array.buffers[0]);
@@ -160,7 +165,7 @@ TEST(ArrayTest, ArrayTestSetBuffer) {
   ArrowBufferAppend(&buffer2, data, strlen(data));
 
   struct ArrowArray array;
-  ASSERT_EQ(ArrowArrayInit(&array, NANOARROW_TYPE_STRING), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_STRING), NANOARROW_OK);
   EXPECT_EQ(ArrowArraySetBuffer(&array, 0, &buffer0), NANOARROW_OK);
   EXPECT_EQ(ArrowArraySetBuffer(&array, 1, &buffer1), NANOARROW_OK);
   EXPECT_EQ(ArrowArraySetBuffer(&array, 2, &buffer2), NANOARROW_OK);
@@ -188,7 +193,7 @@ TEST(ArrayTest, ArrayTestBuildByBuffer) {
 
   struct ArrowArray array;
   struct ArrowError error;
-  ASSERT_EQ(ArrowArrayInit(&array, NANOARROW_TYPE_STRING), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_STRING), NANOARROW_OK);
 
   ASSERT_EQ(ArrowBitmapReserve(ArrowArrayValidityBitmap(&array), 100), NANOARROW_OK);
   ArrowBitmapAppendInt8Unsafe(ArrowArrayValidityBitmap(&array), validity_array, 7);
@@ -232,7 +237,7 @@ TEST(ArrayTest, ArrayTestBuildByBuffer) {
 
 TEST(ArrayTest, ArrayTestAppendToNullArray) {
   struct ArrowArray array;
-  ASSERT_EQ(ArrowArrayInit(&array, NANOARROW_TYPE_NA), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_NA), NANOARROW_OK);
 
   EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendNull(&array, 0), NANOARROW_OK);
@@ -248,7 +253,7 @@ TEST(ArrayTest, ArrayTestAppendToNullArray) {
   ARROW_EXPECT_OK(expected_array);
   EXPECT_TRUE(arrow_array.ValueUnsafe()->Equals(expected_array.ValueUnsafe()));
 
-  ASSERT_EQ(ArrowArrayInit(&array, NANOARROW_TYPE_NA), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_NA), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendInt(&array, 0), EINVAL);
   EXPECT_EQ(ArrowArrayAppendUInt(&array, 0), EINVAL);
   EXPECT_EQ(ArrowArrayAppendDouble(&array, 0), EINVAL);
@@ -263,7 +268,7 @@ TEST(ArrayTest, ArrayTestAppendToNullArray) {
 TEST(ArrayTest, ArrayTestAppendToInt64Array) {
   struct ArrowArray array;
 
-  ASSERT_EQ(ArrowArrayInit(&array, NANOARROW_TYPE_INT64), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_INT64), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendInt(&array, 1), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendNull(&array, 2), NANOARROW_OK);
@@ -296,7 +301,7 @@ TEST(ArrayTest, ArrayTestAppendToInt64Array) {
 TEST(ArrayTest, ArrayTestAppendToInt32Array) {
   struct ArrowArray array;
 
-  ASSERT_EQ(ArrowArrayInit(&array, NANOARROW_TYPE_INT32), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_INT32), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendInt(&array, 123), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendInt(&array, std::numeric_limits<int64_t>::max()), EINVAL);
@@ -322,7 +327,7 @@ TEST(ArrayTest, ArrayTestAppendToInt32Array) {
 TEST(ArrayTest, ArrayTestAppendToInt16Array) {
   struct ArrowArray array;
 
-  ASSERT_EQ(ArrowArrayInit(&array, NANOARROW_TYPE_INT16), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_INT16), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendInt(&array, 123), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendInt(&array, std::numeric_limits<int64_t>::max()), EINVAL);
@@ -348,7 +353,7 @@ TEST(ArrayTest, ArrayTestAppendToInt16Array) {
 TEST(ArrayTest, ArrayTestAppendToInt8Array) {
   struct ArrowArray array;
 
-  ASSERT_EQ(ArrowArrayInit(&array, NANOARROW_TYPE_INT8), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_INT8), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendInt(&array, 123), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendInt(&array, std::numeric_limits<int64_t>::max()), EINVAL);
@@ -374,7 +379,7 @@ TEST(ArrayTest, ArrayTestAppendToInt8Array) {
 TEST(ArrayTest, ArrayTestAppendToStringArray) {
   struct ArrowArray array;
 
-  ASSERT_EQ(ArrowArrayInit(&array, NANOARROW_TYPE_STRING), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_STRING), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
 
   // Check that we can reserve
@@ -413,7 +418,7 @@ TEST(ArrayTest, ArrayTestAppendToStringArray) {
 
 TEST(ArrayTest, ArrayTestAppendEmptyToString) {
   struct ArrowArray array;
-  ASSERT_EQ(ArrowArrayInit(&array, NANOARROW_TYPE_STRING), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_STRING), NANOARROW_OK);
   ASSERT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
   ASSERT_EQ(ArrowArrayAppendString(&array, ArrowCharView("")), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayFinishBuilding(&array, nullptr), NANOARROW_OK);
@@ -424,7 +429,7 @@ TEST(ArrayTest, ArrayTestAppendEmptyToString) {
 TEST(ArrayTest, ArrayTestAppendToUInt64Array) {
   struct ArrowArray array;
 
-  ASSERT_EQ(ArrowArrayInit(&array, NANOARROW_TYPE_UINT64), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_UINT64), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendUInt(&array, 1), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendNull(&array, 2), NANOARROW_OK);
@@ -456,7 +461,7 @@ TEST(ArrayTest, ArrayTestAppendToUInt64Array) {
 TEST(ArrayTest, ArrayTestAppendToUInt32Array) {
   struct ArrowArray array;
 
-  ASSERT_EQ(ArrowArrayInit(&array, NANOARROW_TYPE_UINT32), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_UINT32), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendUInt(&array, 1), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendInt(&array, 3), NANOARROW_OK);
@@ -487,7 +492,7 @@ TEST(ArrayTest, ArrayTestAppendToUInt32Array) {
 TEST(ArrayTest, ArrayTestAppendToUInt16Array) {
   struct ArrowArray array;
 
-  ASSERT_EQ(ArrowArrayInit(&array, NANOARROW_TYPE_UINT16), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_UINT16), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendUInt(&array, 1), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendInt(&array, 3), NANOARROW_OK);
@@ -518,7 +523,7 @@ TEST(ArrayTest, ArrayTestAppendToUInt16Array) {
 TEST(ArrayTest, ArrayTestAppendToUInt8Array) {
   struct ArrowArray array;
 
-  ASSERT_EQ(ArrowArrayInit(&array, NANOARROW_TYPE_UINT8), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_UINT8), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendUInt(&array, 1), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendInt(&array, 3), NANOARROW_OK);
@@ -549,7 +554,7 @@ TEST(ArrayTest, ArrayTestAppendToUInt8Array) {
 TEST(ArrayTest, ArrayTestAppendToDoubleArray) {
   struct ArrowArray array;
 
-  ASSERT_EQ(ArrowArrayInit(&array, NANOARROW_TYPE_DOUBLE), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_DOUBLE), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendInt(&array, 1), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendNull(&array, 2), NANOARROW_OK);
@@ -606,7 +611,7 @@ TEST(ArrayTest, ArrayTestAppendToDoubleArray) {
 TEST(ArrayTest, ArrayTestAppendToFloatArray) {
   struct ArrowArray array;
 
-  ASSERT_EQ(ArrowArrayInit(&array, NANOARROW_TYPE_FLOAT), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_FLOAT), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendInt(&array, 1), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendNull(&array, 2), NANOARROW_OK);
@@ -662,7 +667,7 @@ TEST(ArrayTest, ArrayTestAppendToFloatArray) {
 TEST(ArrayTest, ArrayTestAppendToBoolArray) {
   struct ArrowArray array;
 
-  ASSERT_EQ(ArrowArrayInit(&array, NANOARROW_TYPE_BOOL), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_BOOL), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendInt(&array, 1), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendNull(&array, 2), NANOARROW_OK);
@@ -694,7 +699,7 @@ TEST(ArrayTest, ArrayTestAppendToBoolArray) {
 TEST(ArrayTest, ArrayTestAppendToLargeStringArray) {
   struct ArrowArray array;
 
-  ASSERT_EQ(ArrowArrayInit(&array, NANOARROW_TYPE_LARGE_STRING), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_LARGE_STRING), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
 
   // Check that we can reserve
@@ -735,7 +740,8 @@ TEST(ArrayTest, ArrayTestAppendToFixedSizeBinaryArray) {
   struct ArrowArray array;
   struct ArrowSchema schema;
 
-  ASSERT_EQ(ArrowSchemaInitFixedSize(&schema, NANOARROW_TYPE_FIXED_SIZE_BINARY, 5),
+  ArrowSchemaInit(&schema);
+  ASSERT_EQ(ArrowSchemaSetTypeFixedSize(&schema, NANOARROW_TYPE_FIXED_SIZE_BINARY, 5),
             NANOARROW_OK);
 
   ASSERT_EQ(ArrowArrayInitFromSchema(&array, &schema, nullptr), NANOARROW_OK);
@@ -777,10 +783,8 @@ TEST(ArrayTest, ArrayTestAppendToListArray) {
   struct ArrowSchema schema;
   struct ArrowError error;
 
-  ASSERT_EQ(ArrowSchemaInit(&schema, NANOARROW_TYPE_LIST), NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaAllocateChildren(&schema, 1), NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaInit(schema.children[0], NANOARROW_TYPE_INT64), NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaSetName(schema.children[0], "item"), NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_LIST), NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaSetType(schema.children[0], NANOARROW_TYPE_INT64), NANOARROW_OK);
   ASSERT_EQ(ArrowArrayInitFromSchema(&array, &schema, nullptr), NANOARROW_OK);
 
   ASSERT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
@@ -837,10 +841,8 @@ TEST(ArrayTest, ArrayTestAppendToLargeListArray) {
   struct ArrowSchema schema;
   struct ArrowError error;
 
-  ASSERT_EQ(ArrowSchemaInit(&schema, NANOARROW_TYPE_LARGE_LIST), NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaAllocateChildren(&schema, 1), NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaInit(schema.children[0], NANOARROW_TYPE_INT64), NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaSetName(schema.children[0], "item"), NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_LARGE_LIST), NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaSetType(schema.children[0], NANOARROW_TYPE_INT64), NANOARROW_OK);
   ASSERT_EQ(ArrowArrayInitFromSchema(&array, &schema, nullptr), NANOARROW_OK);
 
   ASSERT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
@@ -898,18 +900,11 @@ TEST(ArrayTest, ArrayTestAppendToMapArray) {
   struct ArrowSchema schema;
   struct ArrowError error;
 
-  ASSERT_EQ(ArrowSchemaInit(&schema, NANOARROW_TYPE_MAP), NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaAllocateChildren(&schema, 1), NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaInit(schema.children[0], NANOARROW_TYPE_STRUCT), NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaSetName(schema.children[0], "entries"), NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaAllocateChildren(schema.children[0], 2), NANOARROW_OK);
-
-  ASSERT_EQ(ArrowSchemaInit(schema.children[0]->children[0], NANOARROW_TYPE_INT32),
+  ASSERT_EQ(ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_MAP), NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaSetType(schema.children[0]->children[0], NANOARROW_TYPE_INT32),
             NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaSetName(schema.children[0]->children[0], "key"), NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaInit(schema.children[0]->children[1], NANOARROW_TYPE_STRING),
+  ASSERT_EQ(ArrowSchemaSetType(schema.children[0]->children[1], NANOARROW_TYPE_STRING),
             NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaSetName(schema.children[0]->children[1], "value"), NANOARROW_OK);
 
   ASSERT_EQ(ArrowArrayInitFromSchema(&array, &schema, nullptr), NANOARROW_OK);
 
@@ -969,11 +964,10 @@ TEST(ArrayTest, ArrayTestAppendToFixedSizeListArray) {
   struct ArrowSchema schema;
   struct ArrowError error;
 
-  ASSERT_EQ(ArrowSchemaInitFixedSize(&schema, NANOARROW_TYPE_FIXED_SIZE_LIST, 2),
+  ArrowSchemaInit(&schema);
+  ASSERT_EQ(ArrowSchemaSetTypeFixedSize(&schema, NANOARROW_TYPE_FIXED_SIZE_LIST, 2),
             NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaAllocateChildren(&schema, 1), NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaInit(schema.children[0], NANOARROW_TYPE_INT64), NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaSetName(schema.children[0], "item"), NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaSetType(schema.children[0], NANOARROW_TYPE_INT64), NANOARROW_OK);
   ASSERT_EQ(ArrowArrayInitFromSchema(&array, &schema, nullptr), NANOARROW_OK);
 
   ASSERT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
@@ -1033,9 +1027,10 @@ TEST(ArrayTest, ArrayTestAppendToStructArray) {
   struct ArrowArray array;
   struct ArrowSchema schema;
 
-  ASSERT_EQ(ArrowSchemaInit(&schema, NANOARROW_TYPE_STRUCT), NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_STRUCT), NANOARROW_OK);
   ASSERT_EQ(ArrowSchemaAllocateChildren(&schema, 1), NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaInit(schema.children[0], NANOARROW_TYPE_INT64), NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaInitFromType(schema.children[0], NANOARROW_TYPE_INT64),
+            NANOARROW_OK);
   ASSERT_EQ(ArrowSchemaSetName(schema.children[0], "col1"), NANOARROW_OK);
   ASSERT_EQ(ArrowArrayInitFromSchema(&array, &schema, nullptr), NANOARROW_OK);
 
@@ -1078,7 +1073,7 @@ TEST(ArrayTest, ArrayTestAppendToStructArray) {
 TEST(ArrayTest, ArrayViewTestBasic) {
   struct ArrowArrayView array_view;
   struct ArrowError error;
-  ArrowArrayViewInit(&array_view, NANOARROW_TYPE_INT32);
+  ArrowArrayViewInitFromType(&array_view, NANOARROW_TYPE_INT32);
 
   EXPECT_EQ(array_view.array, nullptr);
   EXPECT_EQ(array_view.storage_type, NANOARROW_TYPE_INT32);
@@ -1094,7 +1089,7 @@ TEST(ArrayTest, ArrayViewTestBasic) {
   struct ArrowArray array;
 
   // Build with no validity buffer
-  ArrowArrayInit(&array, NANOARROW_TYPE_INT32);
+  ArrowArrayInitFromType(&array, NANOARROW_TYPE_INT32);
   ASSERT_EQ(ArrowBufferAppendInt32(ArrowArrayBuffer(&array, 1), 11), NANOARROW_OK);
   ASSERT_EQ(ArrowBufferAppendInt32(ArrowArrayBuffer(&array, 1), 12), NANOARROW_OK);
   ASSERT_EQ(ArrowBufferAppendInt32(ArrowArrayBuffer(&array, 1), 13), NANOARROW_OK);
@@ -1120,7 +1115,7 @@ TEST(ArrayTest, ArrayViewTestBasic) {
 
   // Expect error for the wrong number of buffers
   ArrowArrayViewReset(&array_view);
-  ArrowArrayViewInit(&array_view, NANOARROW_TYPE_STRING);
+  ArrowArrayViewInitFromType(&array_view, NANOARROW_TYPE_STRING);
   EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), EINVAL);
 
   array.release(&array);
@@ -1129,11 +1124,11 @@ TEST(ArrayTest, ArrayViewTestBasic) {
 
 TEST(ArrayTest, ArrayViewTestMove) {
   struct ArrowArrayView array_view;
-  ArrowArrayViewInit(&array_view, NANOARROW_TYPE_STRING);
+  ArrowArrayViewInitFromType(&array_view, NANOARROW_TYPE_STRING);
   ASSERT_EQ(array_view.storage_type, NANOARROW_TYPE_STRING);
 
   struct ArrowArrayView array_view2;
-  ArrowArrayViewInit(&array_view2, NANOARROW_TYPE_UNINITIALIZED);
+  ArrowArrayViewInitFromType(&array_view2, NANOARROW_TYPE_UNINITIALIZED);
   ASSERT_EQ(array_view2.storage_type, NANOARROW_TYPE_UNINITIALIZED);
 
   ArrowArrayViewMove(&array_view, &array_view2);
@@ -1146,7 +1141,7 @@ TEST(ArrayTest, ArrayViewTestMove) {
 TEST(ArrayTest, ArrayViewTestString) {
   struct ArrowArrayView array_view;
   struct ArrowError error;
-  ArrowArrayViewInit(&array_view, NANOARROW_TYPE_STRING);
+  ArrowArrayViewInitFromType(&array_view, NANOARROW_TYPE_STRING);
 
   EXPECT_EQ(array_view.array, nullptr);
   EXPECT_EQ(array_view.storage_type, NANOARROW_TYPE_STRING);
@@ -1171,7 +1166,7 @@ TEST(ArrayTest, ArrayViewTestString) {
   struct ArrowArray array;
 
   // Build + check zero length
-  ASSERT_EQ(ArrowArrayInit(&array, NANOARROW_TYPE_STRING), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_STRING), NANOARROW_OK);
   array.null_count = 0;
   EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), NANOARROW_OK);
   EXPECT_EQ(array_view.buffer_views[0].n_bytes, 0);
@@ -1198,7 +1193,7 @@ TEST(ArrayTest, ArrayViewTestString) {
 TEST(ArrayTest, ArrayViewTestLargeString) {
   struct ArrowArrayView array_view;
   struct ArrowError error;
-  ArrowArrayViewInit(&array_view, NANOARROW_TYPE_LARGE_STRING);
+  ArrowArrayViewInitFromType(&array_view, NANOARROW_TYPE_LARGE_STRING);
 
   EXPECT_EQ(array_view.array, nullptr);
   EXPECT_EQ(array_view.storage_type, NANOARROW_TYPE_LARGE_STRING);
@@ -1223,7 +1218,7 @@ TEST(ArrayTest, ArrayViewTestLargeString) {
   struct ArrowArray array;
 
   // Build + check zero length
-  ASSERT_EQ(ArrowArrayInit(&array, NANOARROW_TYPE_STRING), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_STRING), NANOARROW_OK);
   array.null_count = 0;
   EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), NANOARROW_OK);
   EXPECT_EQ(array_view.buffer_views[0].n_bytes, 0);
@@ -1249,7 +1244,7 @@ TEST(ArrayTest, ArrayViewTestLargeString) {
 
 TEST(ArrayTest, ArrayViewTestStruct) {
   struct ArrowArrayView array_view;
-  ArrowArrayViewInit(&array_view, NANOARROW_TYPE_STRUCT);
+  ArrowArrayViewInitFromType(&array_view, NANOARROW_TYPE_STRUCT);
 
   EXPECT_EQ(array_view.array, nullptr);
   EXPECT_EQ(array_view.storage_type, NANOARROW_TYPE_STRUCT);
@@ -1263,9 +1258,9 @@ TEST(ArrayTest, ArrayViewTestStruct) {
 
   EXPECT_EQ(ArrowArrayViewAllocateChildren(&array_view, 2), NANOARROW_OK);
   EXPECT_EQ(array_view.n_children, 2);
-  ArrowArrayViewInit(array_view.children[0], NANOARROW_TYPE_INT32);
+  ArrowArrayViewInitFromType(array_view.children[0], NANOARROW_TYPE_INT32);
   EXPECT_EQ(array_view.children[0]->storage_type, NANOARROW_TYPE_INT32);
-  ArrowArrayViewInit(array_view.children[1], NANOARROW_TYPE_NA);
+  ArrowArrayViewInitFromType(array_view.children[1], NANOARROW_TYPE_NA);
   EXPECT_EQ(array_view.children[1]->storage_type, NANOARROW_TYPE_NA);
 
   ArrowArrayViewSetLength(&array_view, 5);
@@ -1280,7 +1275,7 @@ TEST(ArrayTest, ArrayViewTestStruct) {
 
 TEST(ArrayTest, ArrayViewTestList) {
   struct ArrowArrayView array_view;
-  ArrowArrayViewInit(&array_view, NANOARROW_TYPE_LIST);
+  ArrowArrayViewInitFromType(&array_view, NANOARROW_TYPE_LIST);
 
   EXPECT_EQ(array_view.array, nullptr);
   EXPECT_EQ(array_view.storage_type, NANOARROW_TYPE_LIST);
@@ -1291,7 +1286,7 @@ TEST(ArrayTest, ArrayViewTestList) {
 
   EXPECT_EQ(ArrowArrayViewAllocateChildren(&array_view, 1), NANOARROW_OK);
   EXPECT_EQ(array_view.n_children, 1);
-  ArrowArrayViewInit(array_view.children[0], NANOARROW_TYPE_INT32);
+  ArrowArrayViewInitFromType(array_view.children[0], NANOARROW_TYPE_INT32);
   EXPECT_EQ(array_view.children[0]->storage_type, NANOARROW_TYPE_INT32);
 
   ArrowArrayViewSetLength(&array_view, 5);
@@ -1303,7 +1298,7 @@ TEST(ArrayTest, ArrayViewTestList) {
 
 TEST(ArrayTest, ArrayViewTestLargeList) {
   struct ArrowArrayView array_view;
-  ArrowArrayViewInit(&array_view, NANOARROW_TYPE_LARGE_LIST);
+  ArrowArrayViewInitFromType(&array_view, NANOARROW_TYPE_LARGE_LIST);
 
   EXPECT_EQ(array_view.array, nullptr);
   EXPECT_EQ(array_view.storage_type, NANOARROW_TYPE_LARGE_LIST);
@@ -1314,7 +1309,7 @@ TEST(ArrayTest, ArrayViewTestLargeList) {
 
   EXPECT_EQ(ArrowArrayViewAllocateChildren(&array_view, 1), NANOARROW_OK);
   EXPECT_EQ(array_view.n_children, 1);
-  ArrowArrayViewInit(array_view.children[0], NANOARROW_TYPE_INT32);
+  ArrowArrayViewInitFromType(array_view.children[0], NANOARROW_TYPE_INT32);
   EXPECT_EQ(array_view.children[0]->storage_type, NANOARROW_TYPE_INT32);
 
   ArrowArrayViewSetLength(&array_view, 5);
@@ -1326,7 +1321,7 @@ TEST(ArrayTest, ArrayViewTestLargeList) {
 
 TEST(ArrayTest, ArrayViewTestFixedSizeList) {
   struct ArrowArrayView array_view;
-  ArrowArrayViewInit(&array_view, NANOARROW_TYPE_FIXED_SIZE_LIST);
+  ArrowArrayViewInitFromType(&array_view, NANOARROW_TYPE_FIXED_SIZE_LIST);
   array_view.layout.child_size_elements = 3;
 
   EXPECT_EQ(array_view.array, nullptr);
@@ -1336,7 +1331,7 @@ TEST(ArrayTest, ArrayViewTestFixedSizeList) {
 
   EXPECT_EQ(ArrowArrayViewAllocateChildren(&array_view, 1), NANOARROW_OK);
   EXPECT_EQ(array_view.n_children, 1);
-  ArrowArrayViewInit(array_view.children[0], NANOARROW_TYPE_INT32);
+  ArrowArrayViewInitFromType(array_view.children[0], NANOARROW_TYPE_INT32);
   EXPECT_EQ(array_view.children[0]->storage_type, NANOARROW_TYPE_INT32);
 
   ArrowArrayViewSetLength(&array_view, 5);
@@ -1352,21 +1347,23 @@ TEST(ArrayTest, ArrayViewTestStructArray) {
   struct ArrowSchema schema;
   struct ArrowError error;
 
-  ASSERT_EQ(ArrowSchemaInit(&schema, NANOARROW_TYPE_STRUCT), NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_STRUCT), NANOARROW_OK);
   ASSERT_EQ(ArrowSchemaAllocateChildren(&schema, 1), NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaInit(schema.children[0], NANOARROW_TYPE_INT32), NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaInitFromType(schema.children[0], NANOARROW_TYPE_INT32),
+            NANOARROW_OK);
 
   EXPECT_EQ(ArrowArrayViewInitFromSchema(&array_view, &schema, &error), NANOARROW_OK);
   EXPECT_EQ(array_view.n_children, 1);
   EXPECT_EQ(array_view.children[0]->storage_type, NANOARROW_TYPE_INT32);
 
-  ASSERT_EQ(ArrowArrayInit(&array, NANOARROW_TYPE_STRUCT), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_STRUCT), NANOARROW_OK);
 
   // Expect error for the wrong number of children
   EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), EINVAL);
 
   ASSERT_EQ(ArrowArrayAllocateChildren(&array, 1), NANOARROW_OK);
-  ASSERT_EQ(ArrowArrayInit(array.children[0], NANOARROW_TYPE_INT32), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayInitFromType(array.children[0], NANOARROW_TYPE_INT32),
+            NANOARROW_OK);
 
   // Expect error for the wrong number of child elements
   array.length = 1;
@@ -1392,18 +1389,19 @@ TEST(ArrayTest, ArrayViewTestFixedSizeListArray) {
   struct ArrowSchema schema;
   struct ArrowError error;
 
-  ASSERT_EQ(ArrowSchemaInitFixedSize(&schema, NANOARROW_TYPE_FIXED_SIZE_LIST, 3),
+  ArrowSchemaInit(&schema);
+  ASSERT_EQ(ArrowSchemaSetTypeFixedSize(&schema, NANOARROW_TYPE_FIXED_SIZE_LIST, 3),
             NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaAllocateChildren(&schema, 1), NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaInit(schema.children[0], NANOARROW_TYPE_INT32), NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaSetType(schema.children[0], NANOARROW_TYPE_INT32), NANOARROW_OK);
 
   EXPECT_EQ(ArrowArrayViewInitFromSchema(&array_view, &schema, &error), NANOARROW_OK);
   EXPECT_EQ(array_view.n_children, 1);
   EXPECT_EQ(array_view.children[0]->storage_type, NANOARROW_TYPE_INT32);
 
-  ASSERT_EQ(ArrowArrayInit(&array, NANOARROW_TYPE_FIXED_SIZE_LIST), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_FIXED_SIZE_LIST), NANOARROW_OK);
   ASSERT_EQ(ArrowArrayAllocateChildren(&array, 1), NANOARROW_OK);
-  ASSERT_EQ(ArrowArrayInit(array.children[0], NANOARROW_TYPE_INT32), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayInitFromType(array.children[0], NANOARROW_TYPE_INT32),
+            NANOARROW_OK);
 
   // Expect error for the wrong number of child elements
   array.length = 1;
diff --git a/src/nanoarrow/nanoarrow.h b/src/nanoarrow/nanoarrow.h
index 4bea678..5c31bb8 100644
--- a/src/nanoarrow/nanoarrow.h
+++ b/src/nanoarrow/nanoarrow.h
@@ -50,12 +50,19 @@
 #define ArrowErrorSet NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowErrorSet)
 #define ArrowLayoutInit NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowLayoutInit)
 #define ArrowSchemaInit NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowSchemaInit)
-#define ArrowSchemaInitFixedSize \
-  NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowSchemaInitFixedSize)
-#define ArrowSchemaInitDecimal \
-  NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowSchemaInitDecimal)
-#define ArrowSchemaInitDateTime \
-  NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowSchemaInitDateTime)
+#define ArrowSchemaInitFromType \
+  NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowSchemaInitFromType)
+#define ArrowSchemaSetType NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowSchemaSetType)
+#define ArrowSchemaSetTypeStruct \
+  NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowSchemaSetTypeStruct)
+#define ArrowSchemaSetTypeFixedSize \
+  NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowSchemaSetTypeFixedSize)
+#define ArrowSchemaSetTypeDecimal \
+  NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowSchemaSetTypeDecimal)
+#define ArrowSchemaSetTypeDateTime \
+  NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowSchemaSetTypeDateTime)
+#define ArrowSchemaSetTypeUnion \
+  NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowSchemaSetTypeUnion)
 #define ArrowSchemaDeepCopy NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowSchemaDeepCopy)
 #define ArrowSchemaSetFormat NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowSchemaSetFormat)
 #define ArrowSchemaSetName NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowSchemaSetName)
@@ -82,7 +89,8 @@
   NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowMetadataBuilderRemove)
 #define ArrowSchemaViewInit NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowSchemaViewInit)
 #define ArrowSchemaToString NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowSchemaToString)
-#define ArrowArrayInit NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowArrayInit)
+#define ArrowArrayInitFromType \
+  NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowArrayInitFromType)
 #define ArrowArrayInitFromSchema \
   NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowArrayInitFromSchema)
 #define ArrowArrayAllocateChildren \
@@ -95,7 +103,8 @@
 #define ArrowArrayReserve NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowArrayReserve)
 #define ArrowArrayFinishBuilding \
   NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowArrayFinishBuilding)
-#define ArrowArrayViewInit NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowArrayViewInit)
+#define ArrowArrayViewInitFromType \
+  NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowArrayViewInitFromType)
 #define ArrowArrayViewInitFromSchema \
   NANOARROW_SYMBOL(NANOARROW_NAMESPACE, ArrowArrayViewInitFromSchema)
 #define ArrowArrayViewAllocateChildren \
@@ -215,12 +224,20 @@ static inline struct ArrowStringView ArrowCharView(const char* value);
 ///
 /// @{
 
-/// \brief Initialize the fields of a schema
+/// \brief Initialize an ArrowSchema
 ///
 /// Initializes the fields and release callback of schema_out. Caller
 /// is responsible for calling the schema->release callback if
 /// NANOARROW_OK is returned.
-ArrowErrorCode ArrowSchemaInit(struct ArrowSchema* schema, enum ArrowType type);
+void ArrowSchemaInit(struct ArrowSchema* schema);
+
+/// \brief Initialize an ArrowSchema from an ArrowType
+///
+/// A convenience constructor for that calls ArrowSchemaInit() and
+/// ArrowSchemaSetType() for the common case of constructing an
+/// unparameterized type. The caller is responsible for calling the schema->release
+/// callback if NANOARROW_OK is returned.
+ArrowErrorCode ArrowSchemaInitFromType(struct ArrowSchema* schema, enum ArrowType type);
 
 /// \brief Get a human-readable summary of a Schema
 ///
@@ -231,31 +248,63 @@ ArrowErrorCode ArrowSchemaInit(struct ArrowSchema* schema, enum ArrowType type);
 int64_t ArrowSchemaToString(struct ArrowSchema* schema, char* out, int64_t n,
                             char recursive);
 
-/// \brief Initialize the fields of a fixed-size schema
+/// \brief Set the format field of a schema from an ArrowType
+///
+/// Initializes the fields and release callback of schema_out. For
+/// NANOARROW_TYPE_LIST, NANOARROW_TYPE_LARGE_LIST, and
+/// NANOARROW_TYPE_MAP, the appropriate number of children are
+/// allocated, initialized, and named; however, the caller must
+/// ArrowSchemaSetType() on the preinitialized children. Schema must have been initialized
+/// using ArrowSchemaInit() or ArrowSchemaDeepCopy().
+ArrowErrorCode ArrowSchemaSetType(struct ArrowSchema* schema, enum ArrowType type);
+
+/// \brief Set the format field and initialize children of a struct schema
+///
+/// The specified number of children are initialized; however, the caller is responsible
+/// for calling ArrowSchemaSetType() and ArrowSchemaSetName() on each child.
+/// Schema must have been initialized using ArrowSchemaInit() or ArrowSchemaDeepCopy().
+ArrowErrorCode ArrowSchemaSetTypeStruct(struct ArrowSchema* schema, int64_t n_children);
+
+/// \brief Set the format field of a fixed-size schema
 ///
 /// Returns EINVAL for fixed_size <= 0 or for data_type that is not
 /// NANOARROW_TYPE_FIXED_SIZE_BINARY or NANOARROW_TYPE_FIXED_SIZE_LIST.
-ArrowErrorCode ArrowSchemaInitFixedSize(struct ArrowSchema* schema,
-                                        enum ArrowType data_type, int32_t fixed_size);
+/// For NANOARROW_TYPE_FIXED_SIZE_LIST, the appropriate number of children are
+/// allocated, initialized, and named; however, the caller must
+/// ArrowSchemaSetType() the first child. Schema must have been initialized using
+/// ArrowSchemaInit() or ArrowSchemaDeepCopy().
+ArrowErrorCode ArrowSchemaSetTypeFixedSize(struct ArrowSchema* schema,
+                                           enum ArrowType data_type, int32_t fixed_size);
 
-/// \brief Initialize the fields of a decimal schema
+/// \brief Set the format field of a decimal schema
 ///
 /// Returns EINVAL for scale <= 0 or for data_type that is not
-/// NANOARROW_TYPE_DECIMAL128 or NANOARROW_TYPE_DECIMAL256.
-ArrowErrorCode ArrowSchemaInitDecimal(struct ArrowSchema* schema,
-                                      enum ArrowType data_type, int32_t decimal_precision,
-                                      int32_t decimal_scale);
+/// NANOARROW_TYPE_DECIMAL128 or NANOARROW_TYPE_DECIMAL256. Schema must have been
+/// initialized using ArrowSchemaInit() or ArrowSchemaDeepCopy().
+ArrowErrorCode ArrowSchemaSetTypeDecimal(struct ArrowSchema* schema,
+                                         enum ArrowType data_type,
+                                         int32_t decimal_precision,
+                                         int32_t decimal_scale);
 
-/// \brief Initialize the fields of a time, timestamp, or duration schema
+/// \brief Set the format field of a time, timestamp, or duration schema
 ///
 /// Returns EINVAL for data_type that is not
 /// NANOARROW_TYPE_TIME32, NANOARROW_TYPE_TIME64,
 /// NANOARROW_TYPE_TIMESTAMP, or NANOARROW_TYPE_DURATION. The
-/// timezone parameter must be NULL for a non-timestamp data_type.
-ArrowErrorCode ArrowSchemaInitDateTime(struct ArrowSchema* schema,
-                                       enum ArrowType data_type,
-                                       enum ArrowTimeUnit time_unit,
-                                       const char* timezone);
+/// timezone parameter must be NULL for a non-timestamp data_type. Schema must have been
+/// initialized using ArrowSchemaInit() or ArrowSchemaDeepCopy().
+ArrowErrorCode ArrowSchemaSetTypeDateTime(struct ArrowSchema* schema,
+                                          enum ArrowType data_type,
+                                          enum ArrowTimeUnit time_unit,
+                                          const char* timezone);
+
+/// \brief Seet the format field of a union schema
+///
+/// Returns EINVAL for a data_type that is not NANOARROW_TYPE_DENSE_UNION
+/// or NANOARROW_TYPE_SPARSE_UNION. The specified number of children are
+/// allocated, and initialized.
+ArrowErrorCode ArrowSchemaSetTypeUnion(struct ArrowSchema* schema,
+                                       enum ArrowType data_type, int64_t n_children);
 
 /// \brief Make a (recursive) copy of a schema
 ///
@@ -265,33 +314,33 @@ ArrowErrorCode ArrowSchemaDeepCopy(struct ArrowSchema* schema,
 
 /// \brief Copy format into schema->format
 ///
-/// schema must have been allocated using ArrowSchemaInit() or
+/// schema must have been allocated using ArrowSchemaInitFromType() or
 /// ArrowSchemaDeepCopy().
 ArrowErrorCode ArrowSchemaSetFormat(struct ArrowSchema* schema, const char* format);
 
 /// \brief Copy name into schema->name
 ///
-/// schema must have been allocated using ArrowSchemaInit() or
+/// schema must have been allocated using ArrowSchemaInitFromType() or
 /// ArrowSchemaDeepCopy().
 ArrowErrorCode ArrowSchemaSetName(struct ArrowSchema* schema, const char* name);
 
 /// \brief Copy metadata into schema->metadata
 ///
-/// schema must have been allocated using ArrowSchemaInit() or
+/// schema must have been allocated using ArrowSchemaInitFromType() or
 /// ArrowSchemaDeepCopy.
 ArrowErrorCode ArrowSchemaSetMetadata(struct ArrowSchema* schema, const char* metadata);
 
 /// \brief Allocate the schema->children array
 ///
 /// Includes the memory for each child struct ArrowSchema.
-/// schema must have been allocated using ArrowSchemaInit() or
+/// schema must have been allocated using ArrowSchemaInitFromType() or
 /// ArrowSchemaDeepCopy().
 ArrowErrorCode ArrowSchemaAllocateChildren(struct ArrowSchema* schema,
                                            int64_t n_children);
 
 /// \brief Allocate the schema->dictionary member
 ///
-/// schema must have been allocated using ArrowSchemaInit() or
+/// schema must have been allocated using ArrowSchemaInitFromType() or
 /// ArrowSchemaDeepCopy().
 ArrowErrorCode ArrowSchemaAllocateDictionary(struct ArrowSchema* schema);
 
@@ -668,7 +717,8 @@ static inline void ArrowBitmapReset(struct ArrowBitmap* bitmap);
 /// Initializes the fields and release callback of array. Caller
 /// is responsible for calling the array->release callback if
 /// NANOARROW_OK is returned.
-ArrowErrorCode ArrowArrayInit(struct ArrowArray* array, enum ArrowType storage_type);
+ArrowErrorCode ArrowArrayInitFromType(struct ArrowArray* array,
+                                      enum ArrowType storage_type);
 
 /// \brief Initialize the contents of an ArrowArray from an ArrowSchema
 ///
@@ -682,37 +732,37 @@ ArrowErrorCode ArrowArrayInitFromSchema(struct ArrowArray* array,
 ///
 /// Includes the memory for each child struct ArrowArray,
 /// whose members are marked as released and may be subsequently initialized
-/// with ArrowArrayInit() or moved from an existing ArrowArray.
-/// schema must have been allocated using ArrowArrayInit().
+/// with ArrowArrayInitFromType() or moved from an existing ArrowArray.
+/// schema must have been allocated using ArrowArrayInitFromType().
 ArrowErrorCode ArrowArrayAllocateChildren(struct ArrowArray* array, int64_t n_children);
 
 /// \brief Allocate the array->dictionary member
 ///
 /// Includes the memory for the struct ArrowArray, whose contents
 /// is marked as released and may be subsequently initialized
-/// with ArrowArrayInit() or moved from an existing ArrowArray.
-/// array must have been allocated using ArrowArrayInit()
+/// with ArrowArrayInitFromType() or moved from an existing ArrowArray.
+/// array must have been allocated using ArrowArrayInitFromType()
 ArrowErrorCode ArrowArrayAllocateDictionary(struct ArrowArray* array);
 
 /// \brief Set the validity bitmap of an ArrowArray
 ///
-/// array must have been allocated using ArrowArrayInit()
+/// array must have been allocated using ArrowArrayInitFromType()
 void ArrowArraySetValidityBitmap(struct ArrowArray* array, struct ArrowBitmap* bitmap);
 
 /// \brief Set a buffer of an ArrowArray
 ///
-/// array must have been allocated using ArrowArrayInit()
+/// array must have been allocated using ArrowArrayInitFromType()
 ArrowErrorCode ArrowArraySetBuffer(struct ArrowArray* array, int64_t i,
                                    struct ArrowBuffer* buffer);
 
 /// \brief Get the validity bitmap of an ArrowArray
 ///
-/// array must have been allocated using ArrowArrayInit()
+/// array must have been allocated using ArrowArrayInitFromType()
 static inline struct ArrowBitmap* ArrowArrayValidityBitmap(struct ArrowArray* array);
 
 /// \brief Get a buffer of an ArrowArray
 ///
-/// array must have been allocated using ArrowArrayInit()
+/// array must have been allocated using ArrowArrayInitFromType()
 static inline struct ArrowBuffer* ArrowArrayBuffer(struct ArrowArray* array, int64_t i);
 
 /// \brief Start element-wise appending to an ArrowArray
@@ -720,7 +770,7 @@ static inline struct ArrowBuffer* ArrowArrayBuffer(struct ArrowArray* array, int
 /// Initializes any values needed to use ArrowArrayAppend*() functions.
 /// All element-wise appenders append by value and return EINVAL if the exact value
 /// cannot be represented by the underlying storage type.
-/// array must have been allocated using ArrowArrayInit()
+/// array must have been allocated using ArrowArrayInitFromType()
 static inline ArrowErrorCode ArrowArrayStartAppending(struct ArrowArray* array);
 
 /// \brief Reserve space for future appends
@@ -788,7 +838,7 @@ static inline ArrowErrorCode ArrowArrayFinishElement(struct ArrowArray* array);
 /// \brief Shrink buffer capacity to the size required
 ///
 /// Also applies shrinking to any child arrays. array must have been allocated using
-/// ArrowArrayInit
+/// ArrowArrayInitFromType
 static inline ArrowErrorCode ArrowArrayShrinkToFit(struct ArrowArray* array);
 
 /// \brief Finish building an ArrowArray
@@ -796,7 +846,7 @@ static inline ArrowErrorCode ArrowArrayShrinkToFit(struct ArrowArray* array);
 /// Flushes any pointers from internal buffers that may have been reallocated
 /// into the array->buffers array and checks the actual size of the buffers
 /// against the expected size based on the final length.
-/// array must have been allocated using ArrowArrayInit()
+/// array must have been allocated using ArrowArrayInitFromType()
 ArrowErrorCode ArrowArrayFinishBuilding(struct ArrowArray* array,
                                         struct ArrowError* error);
 
@@ -809,7 +859,8 @@ ArrowErrorCode ArrowArrayFinishBuilding(struct ArrowArray* array,
 /// @{
 
 /// \brief Initialize the contents of an ArrowArrayView
-void ArrowArrayViewInit(struct ArrowArrayView* array_view, enum ArrowType storage_type);
+void ArrowArrayViewInitFromType(struct ArrowArrayView* array_view,
+                                enum ArrowType storage_type);
 
 /// \brief Move an ArrowArrayView
 ///
diff --git a/src/nanoarrow/nanoarrow.hpp b/src/nanoarrow/nanoarrow.hpp
index ad851ea..1fe25db 100644
--- a/src/nanoarrow/nanoarrow.hpp
+++ b/src/nanoarrow/nanoarrow.hpp
@@ -93,7 +93,7 @@ static inline void move_pointer(struct ArrowBitmap* src, struct ArrowBitmap* dst
 static inline void release_pointer(struct ArrowBitmap* data) { ArrowBitmapReset(data); }
 
 static inline void init_pointer(struct ArrowArrayView* data) {
-  ArrowArrayViewInit(data, NANOARROW_TYPE_UNINITIALIZED);
+  ArrowArrayViewInitFromType(data, NANOARROW_TYPE_UNINITIALIZED);
 }
 
 static inline void move_pointer(struct ArrowArrayView* src, struct ArrowArrayView* dst) {
diff --git a/src/nanoarrow/nanoarrow_hpp_test.cc b/src/nanoarrow/nanoarrow_hpp_test.cc
index d8c9033..b3ed58a 100644
--- a/src/nanoarrow/nanoarrow_hpp_test.cc
+++ b/src/nanoarrow/nanoarrow_hpp_test.cc
@@ -23,7 +23,7 @@ TEST(NanoarrowHppTest, NanoarrowHppUniqueArrayTest) {
   nanoarrow::UniqueArray array;
   EXPECT_EQ(array->release, nullptr);
 
-  ArrowArrayInit(array.get(), NANOARROW_TYPE_INT32);
+  ArrowArrayInitFromType(array.get(), NANOARROW_TYPE_INT32);
   ASSERT_EQ(ArrowArrayStartAppending(array.get()), NANOARROW_OK);
   ASSERT_EQ(ArrowArrayAppendInt(array.get(), 123), NANOARROW_OK);
   ASSERT_EQ(ArrowArrayFinishBuilding(array.get(), nullptr), NANOARROW_OK);
@@ -48,7 +48,7 @@ TEST(NanoarrowHppTest, NanoarrowHppUniqueSchemaTest) {
   nanoarrow::UniqueSchema schema;
   EXPECT_EQ(schema->release, nullptr);
 
-  ArrowSchemaInit(schema.get(), NANOARROW_TYPE_INT32);
+  ArrowSchemaInitFromType(schema.get(), NANOARROW_TYPE_INT32);
   EXPECT_NE(schema->release, nullptr);
   EXPECT_STREQ(schema->format, "i");
 
@@ -73,7 +73,7 @@ TEST(NanoarrowHppTest, NanoarrowHppUniqueArrayStreamTest) {
   EXPECT_EQ(array_stream_default->release, nullptr);
 
   nanoarrow::UniqueSchema schema_in;
-  EXPECT_EQ(ArrowSchemaInit(schema_in.get(), NANOARROW_TYPE_INT32), NANOARROW_OK);
+  EXPECT_EQ(ArrowSchemaInitFromType(schema_in.get(), NANOARROW_TYPE_INT32), NANOARROW_OK);
   auto array_stream = nanoarrow::EmptyArrayStream::MakeUnique(schema_in.get());
   EXPECT_NE(array_stream->release, nullptr);
   EXPECT_EQ(array_stream->get_schema(array_stream.get(), schema.get()), NANOARROW_OK);
@@ -152,7 +152,7 @@ TEST(NanoarrowHppTest, NanoarrowHppUniqueArrayViewTest) {
 
   // Use an ArrayView with children, since an ArrayView with no children
   // doesn't hold any resources
-  ArrowArrayViewInit(array_view.get(), NANOARROW_TYPE_STRUCT);
+  ArrowArrayViewInitFromType(array_view.get(), NANOARROW_TYPE_STRUCT);
   ArrowArrayViewAllocateChildren(array_view.get(), 2);
   EXPECT_EQ(array_view->storage_type, NANOARROW_TYPE_STRUCT);
 
@@ -172,7 +172,7 @@ TEST(NanoarrowHppTest, NanoarrowHppEmptyArrayStreamTest) {
   struct ArrowArray array;
 
   nanoarrow::UniqueSchema schema_in;
-  EXPECT_EQ(ArrowSchemaInit(schema_in.get(), NANOARROW_TYPE_INT32), NANOARROW_OK);
+  EXPECT_EQ(ArrowSchemaInitFromType(schema_in.get(), NANOARROW_TYPE_INT32), NANOARROW_OK);
   auto array_stream = nanoarrow::EmptyArrayStream::MakeUnique(schema_in.get());
 
   EXPECT_EQ(array_stream->get_schema(array_stream.get(), schema.get()), NANOARROW_OK);
@@ -188,19 +188,19 @@ TEST(NanoarrowHppTest, NanoarrowHppVectorArrayStreamTest) {
   nanoarrow::UniqueArrayView array_view;
 
   nanoarrow::UniqueArray array_in;
-  EXPECT_EQ(ArrowArrayInit(array_in.get(), NANOARROW_TYPE_INT32), NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayInitFromType(array_in.get(), NANOARROW_TYPE_INT32), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayStartAppending(array_in.get()), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayAppendInt(array_in.get(), 1234), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayFinishBuilding(array_in.get(), nullptr), NANOARROW_OK);
 
   nanoarrow::UniqueSchema schema_in;
-  EXPECT_EQ(ArrowSchemaInit(schema_in.get(), NANOARROW_TYPE_INT32), NANOARROW_OK);
+  EXPECT_EQ(ArrowSchemaInitFromType(schema_in.get(), NANOARROW_TYPE_INT32), NANOARROW_OK);
 
   auto array_stream =
       nanoarrow::VectorArrayStream::MakeUnique(schema_in.get(), array_in.get());
 
   EXPECT_EQ(array_stream->get_next(array_stream.get(), array.get()), NANOARROW_OK);
-  ArrowArrayViewInit(array_view.get(), NANOARROW_TYPE_INT32);
+  ArrowArrayViewInitFromType(array_view.get(), NANOARROW_TYPE_INT32);
   ASSERT_EQ(ArrowArrayViewSetArray(array_view.get(), array.get(), nullptr), NANOARROW_OK);
   EXPECT_EQ(ArrowArrayViewGetIntUnsafe(array_view.get(), 0), 1234);
   array.reset();
diff --git a/src/nanoarrow/schema.c b/src/nanoarrow/schema.c
index 8b372aa..93735c6 100644
--- a/src/nanoarrow/schema.c
+++ b/src/nanoarrow/schema.c
@@ -130,7 +130,37 @@ static const char* ArrowSchemaFormatTemplate(enum ArrowType data_type) {
   }
 }
 
-ArrowErrorCode ArrowSchemaInit(struct ArrowSchema* schema, enum ArrowType data_type) {
+static int ArrowSchemaInitChildrenIfNeeded(struct ArrowSchema* schema,
+                                           enum ArrowType data_type) {
+  switch (data_type) {
+    case NANOARROW_TYPE_LIST:
+    case NANOARROW_TYPE_LARGE_LIST:
+    case NANOARROW_TYPE_FIXED_SIZE_LIST:
+      NANOARROW_RETURN_NOT_OK(ArrowSchemaAllocateChildren(schema, 1));
+      ArrowSchemaInit(schema->children[0]);
+      NANOARROW_RETURN_NOT_OK(ArrowSchemaSetName(schema->children[0], "item"));
+      break;
+    case NANOARROW_TYPE_MAP:
+      NANOARROW_RETURN_NOT_OK(ArrowSchemaAllocateChildren(schema, 1));
+      NANOARROW_RETURN_NOT_OK(
+          ArrowSchemaInitFromType(schema->children[0], NANOARROW_TYPE_STRUCT));
+      NANOARROW_RETURN_NOT_OK(ArrowSchemaSetName(schema->children[0], "entries"));
+      NANOARROW_RETURN_NOT_OK(ArrowSchemaAllocateChildren(schema->children[0], 2));
+      ArrowSchemaInit(schema->children[0]->children[0]);
+      ArrowSchemaInit(schema->children[0]->children[1]);
+      NANOARROW_RETURN_NOT_OK(
+          ArrowSchemaSetName(schema->children[0]->children[0], "key"));
+      NANOARROW_RETURN_NOT_OK(
+          ArrowSchemaSetName(schema->children[0]->children[1], "value"));
+      break;
+    default:
+      break;
+  }
+
+  return NANOARROW_OK;
+}
+
+void ArrowSchemaInit(struct ArrowSchema* schema) {
   schema->format = NULL;
   schema->name = NULL;
   schema->metadata = NULL;
@@ -140,7 +170,9 @@ ArrowErrorCode ArrowSchemaInit(struct ArrowSchema* schema, enum ArrowType data_t
   schema->dictionary = NULL;
   schema->private_data = NULL;
   schema->release = &ArrowSchemaRelease;
+}
 
+ArrowErrorCode ArrowSchemaSetType(struct ArrowSchema* schema, enum ArrowType data_type) {
   // We don't allocate the dictionary because it has to be nullptr
   // for non-dictionary-encoded arrays.
 
@@ -149,11 +181,30 @@ ArrowErrorCode ArrowSchemaInit(struct ArrowSchema* schema, enum ArrowType data_t
 
   // If data_type isn't recognized and not explicitly unset
   if (template_format == NULL && data_type != NANOARROW_TYPE_UNINITIALIZED) {
-    schema->release(schema);
     return EINVAL;
   }
 
-  int result = ArrowSchemaSetFormat(schema, template_format);
+  NANOARROW_RETURN_NOT_OK(ArrowSchemaSetFormat(schema, template_format));
+
+  // For types with an umabiguous child structure, allocate children
+  return ArrowSchemaInitChildrenIfNeeded(schema, data_type);
+}
+
+ArrowErrorCode ArrowSchemaSetTypeStruct(struct ArrowSchema* schema, int64_t n_children) {
+  NANOARROW_RETURN_NOT_OK(ArrowSchemaSetType(schema, NANOARROW_TYPE_STRUCT));
+  NANOARROW_RETURN_NOT_OK(ArrowSchemaAllocateChildren(schema, n_children));
+  for (int64_t i = 0; i < n_children; i++) {
+    ArrowSchemaInit(schema->children[i]);
+  }
+
+  return NANOARROW_OK;
+}
+
+ArrowErrorCode ArrowSchemaInitFromType(struct ArrowSchema* schema,
+                                       enum ArrowType data_type) {
+  ArrowSchemaInit(schema);
+
+  int result = ArrowSchemaSetType(schema, data_type);
   if (result != NANOARROW_OK) {
     schema->release(schema);
     return result;
@@ -162,12 +213,9 @@ ArrowErrorCode ArrowSchemaInit(struct ArrowSchema* schema, enum ArrowType data_t
   return NANOARROW_OK;
 }
 
-ArrowErrorCode ArrowSchemaInitFixedSize(struct ArrowSchema* schema,
-                                        enum ArrowType data_type, int32_t fixed_size) {
-  NANOARROW_RETURN_NOT_OK(ArrowSchemaInit(schema, NANOARROW_TYPE_UNINITIALIZED));
-
+ArrowErrorCode ArrowSchemaSetTypeFixedSize(struct ArrowSchema* schema,
+                                           enum ArrowType data_type, int32_t fixed_size) {
   if (fixed_size <= 0) {
-    schema->release(schema);
     return EINVAL;
   }
 
@@ -181,27 +229,24 @@ ArrowErrorCode ArrowSchemaInitFixedSize(struct ArrowSchema* schema,
       n_chars = snprintf(buffer, sizeof(buffer), "+w:%d", (int)fixed_size);
       break;
     default:
-      schema->release(schema);
       return EINVAL;
   }
 
   buffer[n_chars] = '\0';
-  int result = ArrowSchemaSetFormat(schema, buffer);
-  if (result != NANOARROW_OK) {
-    schema->release(schema);
-    return result;
+  NANOARROW_RETURN_NOT_OK(ArrowSchemaSetFormat(schema, buffer));
+
+  if (data_type == NANOARROW_TYPE_FIXED_SIZE_LIST) {
+    NANOARROW_RETURN_NOT_OK(ArrowSchemaInitChildrenIfNeeded(schema, data_type));
   }
 
   return NANOARROW_OK;
 }
 
-ArrowErrorCode ArrowSchemaInitDecimal(struct ArrowSchema* schema,
-                                      enum ArrowType data_type, int32_t decimal_precision,
-                                      int32_t decimal_scale) {
-  NANOARROW_RETURN_NOT_OK(ArrowSchemaInit(schema, NANOARROW_TYPE_UNINITIALIZED));
-
+ArrowErrorCode ArrowSchemaSetTypeDecimal(struct ArrowSchema* schema,
+                                         enum ArrowType data_type,
+                                         int32_t decimal_precision,
+                                         int32_t decimal_scale) {
   if (decimal_precision <= 0) {
-    schema->release(schema);
     return EINVAL;
   }
 
@@ -217,19 +262,11 @@ ArrowErrorCode ArrowSchemaInitDecimal(struct ArrowSchema* schema,
                          decimal_scale);
       break;
     default:
-      schema->release(schema);
       return EINVAL;
   }
 
   buffer[n_chars] = '\0';
-
-  int result = ArrowSchemaSetFormat(schema, buffer);
-  if (result != NANOARROW_OK) {
-    schema->release(schema);
-    return result;
-  }
-
-  return NANOARROW_OK;
+  return ArrowSchemaSetFormat(schema, buffer);
 }
 
 static const char* ArrowTimeUnitFormatString(enum ArrowTimeUnit time_unit) {
@@ -247,18 +284,12 @@ static const char* ArrowTimeUnitFormatString(enum ArrowTimeUnit time_unit) {
   }
 }
 
-ArrowErrorCode ArrowSchemaInitDateTime(struct ArrowSchema* schema,
-                                       enum ArrowType data_type,
-                                       enum ArrowTimeUnit time_unit,
-                                       const char* timezone) {
-  int result = ArrowSchemaInit(schema, NANOARROW_TYPE_UNINITIALIZED);
-  if (result != NANOARROW_OK) {
-    return result;
-  }
-
+ArrowErrorCode ArrowSchemaSetTypeDateTime(struct ArrowSchema* schema,
+                                          enum ArrowType data_type,
+                                          enum ArrowTimeUnit time_unit,
+                                          const char* timezone) {
   const char* time_unit_str = ArrowTimeUnitFormatString(time_unit);
   if (time_unit_str == NULL) {
-    schema->release(schema);
     return EINVAL;
   }
 
@@ -268,7 +299,6 @@ ArrowErrorCode ArrowSchemaInitDateTime(struct ArrowSchema* schema,
     case NANOARROW_TYPE_TIME32:
     case NANOARROW_TYPE_TIME64:
       if (timezone != NULL) {
-        schema->release(schema);
         return EINVAL;
       }
       n_chars = snprintf(buffer, sizeof(buffer), "tt%s", time_unit_str);
@@ -281,27 +311,68 @@ ArrowErrorCode ArrowSchemaInitDateTime(struct ArrowSchema* schema,
       break;
     case NANOARROW_TYPE_DURATION:
       if (timezone != NULL) {
-        schema->release(schema);
         return EINVAL;
       }
       n_chars = snprintf(buffer, sizeof(buffer), "tD%s", time_unit_str);
       break;
     default:
-      schema->release(schema);
       return EINVAL;
   }
 
   if (((size_t)n_chars) >= sizeof(buffer)) {
-    schema->release(schema);
     return ERANGE;
   }
 
   buffer[n_chars] = '\0';
 
-  result = ArrowSchemaSetFormat(schema, buffer);
-  if (result != NANOARROW_OK) {
-    schema->release(schema);
-    return result;
+  return ArrowSchemaSetFormat(schema, buffer);
+}
+
+ArrowErrorCode ArrowSchemaSetTypeUnion(struct ArrowSchema* schema,
+                                       enum ArrowType data_type, int64_t n_children) {
+  if (n_children < 0 || n_children > 127) {
+    return EINVAL;
+  }
+
+  // Max valid size would be +ud:0,1,...126 = 401 characters + null terminator
+  char format_out[512];
+  int64_t format_out_size = 512;
+  memset(format_out, 0, format_out_size);
+  int n_chars;
+  char* format_cursor = format_out;
+
+  switch (data_type) {
+    case NANOARROW_TYPE_SPARSE_UNION:
+      n_chars = snprintf(format_cursor, format_out_size, "+us:");
+      format_cursor += n_chars;
+      format_out_size -= n_chars;
+      break;
+    case NANOARROW_TYPE_DENSE_UNION:
+      n_chars = snprintf(format_cursor, format_out_size, "+ud:");
+      format_cursor += n_chars;
+      format_out_size -= n_chars;
+      break;
+    default:
+      return EINVAL;
+  }
+
+  if (n_children > 0) {
+    n_chars = snprintf(format_cursor, format_out_size, "0");
+    format_cursor += n_chars;
+    format_out_size -= n_chars;
+
+    for (int64_t i = 1; i < n_children; i++) {
+      n_chars = snprintf(format_cursor, format_out_size, ",%d", (int)i);
+      format_cursor += n_chars;
+      format_out_size -= n_chars;
+    }
+  }
+
+  NANOARROW_RETURN_NOT_OK(ArrowSchemaSetFormat(schema, format_out));
+
+  NANOARROW_RETURN_NOT_OK(ArrowSchemaAllocateChildren(schema, n_children));
+  for (int64_t i = 0; i < n_children; i++) {
+    ArrowSchemaInit(schema->children[i]);
   }
 
   return NANOARROW_OK;
@@ -413,8 +484,9 @@ ArrowErrorCode ArrowSchemaAllocateDictionary(struct ArrowSchema* schema) {
   return NANOARROW_OK;
 }
 
-int ArrowSchemaDeepCopy(struct ArrowSchema* schema, struct ArrowSchema* schema_out) {
-  NANOARROW_RETURN_NOT_OK(ArrowSchemaInit(schema_out, NANOARROW_TYPE_NA));
+ArrowErrorCode ArrowSchemaDeepCopy(struct ArrowSchema* schema,
+                                   struct ArrowSchema* schema_out) {
+  ArrowSchemaInit(schema_out);
 
   int result = ArrowSchemaSetFormat(schema_out, schema->format);
   if (result != NANOARROW_OK) {
diff --git a/src/nanoarrow/schema_test.cc b/src/nanoarrow/schema_test.cc
index 9fd3cc1..162bc7a 100644
--- a/src/nanoarrow/schema_test.cc
+++ b/src/nanoarrow/schema_test.cc
@@ -35,7 +35,7 @@ std::string ArrowSchemaToStdString(struct ArrowSchema* schema, bool recursive =
 
 TEST(SchemaTest, SchemaInit) {
   struct ArrowSchema schema;
-  ASSERT_EQ(ArrowSchemaInit(&schema, NANOARROW_TYPE_UNINITIALIZED), NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_UNINITIALIZED), NANOARROW_OK);
   ASSERT_EQ(ArrowSchemaAllocateChildren(&schema, 2), NANOARROW_OK);
 
   ASSERT_NE(schema.release, nullptr);
@@ -49,7 +49,7 @@ TEST(SchemaTest, SchemaInit) {
   schema.release(&schema);
   EXPECT_EQ(schema.release, nullptr);
 
-  ASSERT_EQ(ArrowSchemaInit(&schema, NANOARROW_TYPE_UNINITIALIZED), NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_UNINITIALIZED), NANOARROW_OK);
   EXPECT_EQ(ArrowSchemaAllocateChildren(
                 &schema, std::numeric_limits<int64_t>::max() / sizeof(void*)),
             ENOMEM);
@@ -59,7 +59,7 @@ TEST(SchemaTest, SchemaInit) {
 static void ExpectSchemaInitOk(enum ArrowType data_type,
                                std::shared_ptr<DataType> expected_arrow_type) {
   struct ArrowSchema schema;
-  EXPECT_EQ(ArrowSchemaInit(&schema, data_type), NANOARROW_OK);
+  EXPECT_EQ(ArrowSchemaInitFromType(&schema, data_type), NANOARROW_OK);
   auto arrow_type = ImportType(&schema);
   ARROW_EXPECT_OK(arrow_type);
   EXPECT_TRUE(arrow_type.ValueUnsafe()->Equals(expected_arrow_type));
@@ -92,28 +92,24 @@ TEST(SchemaTest, SchemaInitSimple) {
 
 TEST(SchemaTest, SchemaInitSimpleError) {
   struct ArrowSchema schema;
-  EXPECT_EQ(ArrowSchemaInit(&schema, NANOARROW_TYPE_DECIMAL128), EINVAL);
+  EXPECT_EQ(ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_DECIMAL128), EINVAL);
   EXPECT_EQ(schema.release, nullptr);
 }
 
 TEST(SchemaTest, SchemaTestInitNestedList) {
   struct ArrowSchema schema;
 
-  EXPECT_EQ(ArrowSchemaInit(&schema, NANOARROW_TYPE_LIST), NANOARROW_OK);
+  EXPECT_EQ(ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_LIST), NANOARROW_OK);
   EXPECT_STREQ(schema.format, "+l");
-  ASSERT_EQ(ArrowSchemaAllocateChildren(&schema, 1), NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaInit(schema.children[0], NANOARROW_TYPE_INT32), NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaSetName(schema.children[0], "item"), NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaSetType(schema.children[0], NANOARROW_TYPE_INT32), NANOARROW_OK);
 
   auto arrow_type = ImportType(&schema);
   ARROW_EXPECT_OK(arrow_type);
   EXPECT_TRUE(arrow_type.ValueUnsafe()->Equals(list(int32())));
 
-  EXPECT_EQ(ArrowSchemaInit(&schema, NANOARROW_TYPE_LARGE_LIST), NANOARROW_OK);
+  EXPECT_EQ(ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_LARGE_LIST), NANOARROW_OK);
   EXPECT_STREQ(schema.format, "+L");
-  ASSERT_EQ(ArrowSchemaAllocateChildren(&schema, 1), NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaInit(schema.children[0], NANOARROW_TYPE_INT32), NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaSetName(schema.children[0], "item"), NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaSetType(schema.children[0], NANOARROW_TYPE_INT32), NANOARROW_OK);
 
   arrow_type = ImportType(&schema);
   ARROW_EXPECT_OK(arrow_type);
@@ -123,10 +119,11 @@ TEST(SchemaTest, SchemaTestInitNestedList) {
 TEST(SchemaTest, SchemaTestInitNestedStruct) {
   struct ArrowSchema schema;
 
-  EXPECT_EQ(ArrowSchemaInit(&schema, NANOARROW_TYPE_STRUCT), NANOARROW_OK);
+  ArrowSchemaInit(&schema);
+  EXPECT_EQ(ArrowSchemaSetTypeStruct(&schema, 1), NANOARROW_OK);
   EXPECT_STREQ(schema.format, "+s");
-  ASSERT_EQ(ArrowSchemaAllocateChildren(&schema, 1), NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaInit(schema.children[0], NANOARROW_TYPE_INT32), NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaSetType(schema.children[0], NANOARROW_TYPE_INT32),
+            NANOARROW_OK);
   ASSERT_EQ(ArrowSchemaSetName(schema.children[0], "item"), NANOARROW_OK);
 
   auto arrow_type = ImportType(&schema);
@@ -137,18 +134,12 @@ TEST(SchemaTest, SchemaTestInitNestedStruct) {
 TEST(SchemaTest, SchemaTestInitNestedMap) {
   struct ArrowSchema schema;
 
-  EXPECT_EQ(ArrowSchemaInit(&schema, NANOARROW_TYPE_MAP), NANOARROW_OK);
+  EXPECT_EQ(ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_MAP), NANOARROW_OK);
   EXPECT_STREQ(schema.format, "+m");
-  ASSERT_EQ(ArrowSchemaAllocateChildren(&schema, 1), NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaInit(schema.children[0], NANOARROW_TYPE_STRUCT), NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaSetName(schema.children[0], "entries"), NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaAllocateChildren(schema.children[0], 2), NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaInit(schema.children[0]->children[0], NANOARROW_TYPE_INT32),
+  ASSERT_EQ(ArrowSchemaSetType(schema.children[0]->children[0], NANOARROW_TYPE_INT32),
             NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaSetName(schema.children[0]->children[0], "key"), NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaInit(schema.children[0]->children[1], NANOARROW_TYPE_STRING),
+  ASSERT_EQ(ArrowSchemaSetType(schema.children[0]->children[1], NANOARROW_TYPE_STRING),
             NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaSetName(schema.children[0]->children[1], "value"), NANOARROW_OK);
 
   auto arrow_type = ImportType(&schema);
   ARROW_EXPECT_OK(arrow_type);
@@ -157,14 +148,13 @@ TEST(SchemaTest, SchemaTestInitNestedMap) {
 
 TEST(SchemaTest, SchemaInitFixedSize) {
   struct ArrowSchema schema;
+  ArrowSchemaInit(&schema);
 
-  EXPECT_EQ(ArrowSchemaInitFixedSize(&schema, NANOARROW_TYPE_DOUBLE, 1), EINVAL);
-  EXPECT_EQ(schema.release, nullptr);
-  EXPECT_EQ(ArrowSchemaInitFixedSize(&schema, NANOARROW_TYPE_FIXED_SIZE_BINARY, 0),
+  EXPECT_EQ(ArrowSchemaSetTypeFixedSize(&schema, NANOARROW_TYPE_DOUBLE, 1), EINVAL);
+  EXPECT_EQ(ArrowSchemaSetTypeFixedSize(&schema, NANOARROW_TYPE_FIXED_SIZE_BINARY, 0),
             EINVAL);
-  EXPECT_EQ(schema.release, nullptr);
 
-  EXPECT_EQ(ArrowSchemaInitFixedSize(&schema, NANOARROW_TYPE_FIXED_SIZE_BINARY, 45),
+  EXPECT_EQ(ArrowSchemaSetTypeFixedSize(&schema, NANOARROW_TYPE_FIXED_SIZE_BINARY, 45),
             NANOARROW_OK);
   EXPECT_STREQ(schema.format, "w:45");
 
@@ -172,12 +162,11 @@ TEST(SchemaTest, SchemaInitFixedSize) {
   ARROW_EXPECT_OK(arrow_type);
   EXPECT_TRUE(arrow_type.ValueUnsafe()->Equals(fixed_size_binary(45)));
 
-  EXPECT_EQ(ArrowSchemaInitFixedSize(&schema, NANOARROW_TYPE_FIXED_SIZE_LIST, 12),
+  ArrowSchemaInit(&schema);
+  EXPECT_EQ(ArrowSchemaSetTypeFixedSize(&schema, NANOARROW_TYPE_FIXED_SIZE_LIST, 12),
             NANOARROW_OK);
   EXPECT_STREQ(schema.format, "+w:12");
-  ASSERT_EQ(ArrowSchemaAllocateChildren(&schema, 1), NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaInit(schema.children[0], NANOARROW_TYPE_INT32), NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaSetName(schema.children[0], "item"), NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaSetType(schema.children[0], NANOARROW_TYPE_INT32), NANOARROW_OK);
 
   arrow_type = ImportType(&schema);
   ARROW_EXPECT_OK(arrow_type);
@@ -187,12 +176,11 @@ TEST(SchemaTest, SchemaInitFixedSize) {
 TEST(SchemaTest, SchemaInitDecimal) {
   struct ArrowSchema schema;
 
-  EXPECT_EQ(ArrowSchemaInitDecimal(&schema, NANOARROW_TYPE_DECIMAL128, -1, 1), EINVAL);
-  EXPECT_EQ(schema.release, nullptr);
-  EXPECT_EQ(ArrowSchemaInitDecimal(&schema, NANOARROW_TYPE_DOUBLE, 1, 2), EINVAL);
-  EXPECT_EQ(schema.release, nullptr);
+  ArrowSchemaInit(&schema);
+  EXPECT_EQ(ArrowSchemaSetTypeDecimal(&schema, NANOARROW_TYPE_DECIMAL128, -1, 1), EINVAL);
+  EXPECT_EQ(ArrowSchemaSetTypeDecimal(&schema, NANOARROW_TYPE_DOUBLE, 1, 2), EINVAL);
 
-  EXPECT_EQ(ArrowSchemaInitDecimal(&schema, NANOARROW_TYPE_DECIMAL128, 1, 2),
+  EXPECT_EQ(ArrowSchemaSetTypeDecimal(&schema, NANOARROW_TYPE_DECIMAL128, 1, 2),
             NANOARROW_OK);
   EXPECT_STREQ(schema.format, "d:1,2");
 
@@ -200,7 +188,8 @@ TEST(SchemaTest, SchemaInitDecimal) {
   ARROW_EXPECT_OK(arrow_type);
   EXPECT_TRUE(arrow_type.ValueUnsafe()->Equals(decimal128(1, 2)));
 
-  EXPECT_EQ(ArrowSchemaInitDecimal(&schema, NANOARROW_TYPE_DECIMAL256, 3, 4),
+  ArrowSchemaInit(&schema);
+  EXPECT_EQ(ArrowSchemaSetTypeDecimal(&schema, NANOARROW_TYPE_DECIMAL256, 3, 4),
             NANOARROW_OK);
   EXPECT_STREQ(schema.format, "d:3,4,256");
   arrow_type = ImportType(&schema);
@@ -211,30 +200,31 @@ TEST(SchemaTest, SchemaInitDecimal) {
 TEST(SchemaTest, SchemaInitDateTime) {
   struct ArrowSchema schema;
 
-  EXPECT_EQ(ArrowSchemaInitDateTime(&schema, NANOARROW_TYPE_DOUBLE,
-                                    NANOARROW_TIME_UNIT_SECOND, nullptr),
+  ArrowSchemaInit(&schema);
+  EXPECT_EQ(ArrowSchemaSetTypeDateTime(&schema, NANOARROW_TYPE_DOUBLE,
+                                       NANOARROW_TIME_UNIT_SECOND, nullptr),
             EINVAL);
-  EXPECT_EQ(schema.release, nullptr);
 
-  EXPECT_EQ(ArrowSchemaInitDateTime(&schema, NANOARROW_TYPE_TIME32,
-                                    NANOARROW_TIME_UNIT_SECOND, "non-null timezone"),
+  ArrowSchemaInit(&schema);
+  EXPECT_EQ(ArrowSchemaSetTypeDateTime(&schema, NANOARROW_TYPE_TIME32,
+                                       NANOARROW_TIME_UNIT_SECOND, "non-null timezone"),
             EINVAL);
-  EXPECT_EQ(schema.release, nullptr);
 
-  EXPECT_EQ(ArrowSchemaInitDateTime(&schema, NANOARROW_TYPE_DURATION,
-                                    NANOARROW_TIME_UNIT_SECOND, "non-null timezone"),
+  ArrowSchemaInit(&schema);
+  EXPECT_EQ(ArrowSchemaSetTypeDateTime(&schema, NANOARROW_TYPE_DURATION,
+                                       NANOARROW_TIME_UNIT_SECOND, "non-null timezone"),
             EINVAL);
-  EXPECT_EQ(schema.release, nullptr);
 
-  EXPECT_EQ(ArrowSchemaInitDateTime(
+  ArrowSchemaInit(&schema);
+  EXPECT_EQ(ArrowSchemaSetTypeDateTime(
                 &schema, NANOARROW_TYPE_TIMESTAMP, NANOARROW_TIME_UNIT_SECOND,
                 "a really really really really really really really really really really "
                 "long timezone that causes a buffer overflow on snprintf"),
             ERANGE);
-  EXPECT_EQ(schema.release, nullptr);
 
-  EXPECT_EQ(ArrowSchemaInitDateTime(&schema, NANOARROW_TYPE_TIME32,
-                                    NANOARROW_TIME_UNIT_SECOND, NULL),
+  ArrowSchemaInit(&schema);
+  EXPECT_EQ(ArrowSchemaSetTypeDateTime(&schema, NANOARROW_TYPE_TIME32,
+                                       NANOARROW_TIME_UNIT_SECOND, NULL),
             NANOARROW_OK);
   EXPECT_STREQ(schema.format, "tts");
 
@@ -242,8 +232,9 @@ TEST(SchemaTest, SchemaInitDateTime) {
   ARROW_EXPECT_OK(arrow_type);
   EXPECT_TRUE(arrow_type.ValueUnsafe()->Equals(time32(TimeUnit::SECOND)));
 
-  EXPECT_EQ(ArrowSchemaInitDateTime(&schema, NANOARROW_TYPE_TIME64,
-                                    NANOARROW_TIME_UNIT_NANO, NULL),
+  ArrowSchemaInit(&schema);
+  EXPECT_EQ(ArrowSchemaSetTypeDateTime(&schema, NANOARROW_TYPE_TIME64,
+                                       NANOARROW_TIME_UNIT_NANO, NULL),
             NANOARROW_OK);
   EXPECT_STREQ(schema.format, "ttn");
 
@@ -251,8 +242,9 @@ TEST(SchemaTest, SchemaInitDateTime) {
   ARROW_EXPECT_OK(arrow_type);
   EXPECT_TRUE(arrow_type.ValueUnsafe()->Equals(time64(TimeUnit::NANO)));
 
-  EXPECT_EQ(ArrowSchemaInitDateTime(&schema, NANOARROW_TYPE_DURATION,
-                                    NANOARROW_TIME_UNIT_SECOND, NULL),
+  ArrowSchemaInit(&schema);
+  EXPECT_EQ(ArrowSchemaSetTypeDateTime(&schema, NANOARROW_TYPE_DURATION,
+                                       NANOARROW_TIME_UNIT_SECOND, NULL),
             NANOARROW_OK);
   EXPECT_STREQ(schema.format, "tDs");
 
@@ -260,8 +252,9 @@ TEST(SchemaTest, SchemaInitDateTime) {
   ARROW_EXPECT_OK(arrow_type);
   EXPECT_TRUE(arrow_type.ValueUnsafe()->Equals(duration(TimeUnit::SECOND)));
 
-  EXPECT_EQ(ArrowSchemaInitDateTime(&schema, NANOARROW_TYPE_TIMESTAMP,
-                                    NANOARROW_TIME_UNIT_SECOND, NULL),
+  ArrowSchemaInit(&schema);
+  EXPECT_EQ(ArrowSchemaSetTypeDateTime(&schema, NANOARROW_TYPE_TIMESTAMP,
+                                       NANOARROW_TIME_UNIT_SECOND, NULL),
             NANOARROW_OK);
   EXPECT_STREQ(schema.format, "tss:");
 
@@ -269,8 +262,9 @@ TEST(SchemaTest, SchemaInitDateTime) {
   ARROW_EXPECT_OK(arrow_type);
   EXPECT_TRUE(arrow_type.ValueUnsafe()->Equals(timestamp(TimeUnit::SECOND)));
 
-  EXPECT_EQ(ArrowSchemaInitDateTime(&schema, NANOARROW_TYPE_TIMESTAMP,
-                                    NANOARROW_TIME_UNIT_MILLI, NULL),
+  ArrowSchemaInit(&schema);
+  EXPECT_EQ(ArrowSchemaSetTypeDateTime(&schema, NANOARROW_TYPE_TIMESTAMP,
+                                       NANOARROW_TIME_UNIT_MILLI, NULL),
             NANOARROW_OK);
   EXPECT_STREQ(schema.format, "tsm:");
 
@@ -278,8 +272,9 @@ TEST(SchemaTest, SchemaInitDateTime) {
   ARROW_EXPECT_OK(arrow_type);
   EXPECT_TRUE(arrow_type.ValueUnsafe()->Equals(timestamp(TimeUnit::MILLI)));
 
-  EXPECT_EQ(ArrowSchemaInitDateTime(&schema, NANOARROW_TYPE_TIMESTAMP,
-                                    NANOARROW_TIME_UNIT_MICRO, NULL),
+  ArrowSchemaInit(&schema);
+  EXPECT_EQ(ArrowSchemaSetTypeDateTime(&schema, NANOARROW_TYPE_TIMESTAMP,
+                                       NANOARROW_TIME_UNIT_MICRO, NULL),
             NANOARROW_OK);
   EXPECT_STREQ(schema.format, "tsu:");
 
@@ -287,8 +282,9 @@ TEST(SchemaTest, SchemaInitDateTime) {
   ARROW_EXPECT_OK(arrow_type);
   EXPECT_TRUE(arrow_type.ValueUnsafe()->Equals(timestamp(TimeUnit::MICRO)));
 
-  EXPECT_EQ(ArrowSchemaInitDateTime(&schema, NANOARROW_TYPE_TIMESTAMP,
-                                    NANOARROW_TIME_UNIT_NANO, NULL),
+  ArrowSchemaInit(&schema);
+  EXPECT_EQ(ArrowSchemaSetTypeDateTime(&schema, NANOARROW_TYPE_TIMESTAMP,
+                                       NANOARROW_TIME_UNIT_NANO, NULL),
             NANOARROW_OK);
   EXPECT_STREQ(schema.format, "tsn:");
 
@@ -296,8 +292,9 @@ TEST(SchemaTest, SchemaInitDateTime) {
   ARROW_EXPECT_OK(arrow_type);
   EXPECT_TRUE(arrow_type.ValueUnsafe()->Equals(timestamp(TimeUnit::NANO)));
 
-  EXPECT_EQ(ArrowSchemaInitDateTime(&schema, NANOARROW_TYPE_TIMESTAMP,
-                                    NANOARROW_TIME_UNIT_SECOND, "America/Halifax"),
+  ArrowSchemaInit(&schema);
+  EXPECT_EQ(ArrowSchemaSetTypeDateTime(&schema, NANOARROW_TYPE_TIMESTAMP,
+                                       NANOARROW_TIME_UNIT_SECOND, "America/Halifax"),
             NANOARROW_OK);
   EXPECT_STREQ(schema.format, "tss:America/Halifax");
 
@@ -307,9 +304,63 @@ TEST(SchemaTest, SchemaInitDateTime) {
       arrow_type.ValueUnsafe()->Equals(timestamp(TimeUnit::SECOND, "America/Halifax")));
 }
 
+TEST(SchemaTest, SchemaInitUnion) {
+  struct ArrowSchema schema;
+
+  ArrowSchemaInit(&schema);
+  EXPECT_EQ(ArrowSchemaSetTypeUnion(&schema, NANOARROW_TYPE_NA, 1), EINVAL);
+  EXPECT_EQ(ArrowSchemaSetTypeUnion(&schema, NANOARROW_TYPE_SPARSE_UNION, -1), EINVAL);
+  EXPECT_EQ(ArrowSchemaSetTypeUnion(&schema, NANOARROW_TYPE_SPARSE_UNION, 128), EINVAL);
+  schema.release(&schema);
+
+  ArrowSchemaInit(&schema);
+  EXPECT_EQ(ArrowSchemaSetTypeUnion(&schema, NANOARROW_TYPE_SPARSE_UNION, 0), NANOARROW_OK);
+  EXPECT_STREQ(schema.format, "+us:");
+  EXPECT_EQ(schema.n_children, 0);
+  // The zero-case union isn't supported by Arrow C++'s C data inferface implementation
+  schema.release(&schema);
+  
+  ArrowSchemaInit(&schema);
+  EXPECT_EQ(ArrowSchemaSetTypeUnion(&schema, NANOARROW_TYPE_SPARSE_UNION, 1), NANOARROW_OK);
+  EXPECT_EQ(ArrowSchemaSetName(schema.children[0], "u1"), NANOARROW_OK);
+  EXPECT_EQ(ArrowSchemaSetType(schema.children[0], NANOARROW_TYPE_INT32), NANOARROW_OK);
+  EXPECT_STREQ(schema.format, "+us:0");
+  EXPECT_EQ(schema.n_children, 1);
+
+  auto arrow_type = ImportType(&schema);
+  ARROW_EXPECT_OK(arrow_type);
+  EXPECT_TRUE(arrow_type.ValueUnsafe()->Equals(sparse_union({field("u1", int32())})));
+
+  ArrowSchemaInit(&schema);
+  EXPECT_EQ(ArrowSchemaSetTypeUnion(&schema, NANOARROW_TYPE_SPARSE_UNION, 2), NANOARROW_OK);
+  EXPECT_EQ(ArrowSchemaSetName(schema.children[0], "u1"), NANOARROW_OK);
+  EXPECT_EQ(ArrowSchemaSetType(schema.children[0], NANOARROW_TYPE_INT32), NANOARROW_OK);
+  EXPECT_EQ(ArrowSchemaSetName(schema.children[1], "u2"), NANOARROW_OK);
+  EXPECT_EQ(ArrowSchemaSetType(schema.children[1], NANOARROW_TYPE_STRING), NANOARROW_OK);
+  EXPECT_STREQ(schema.format, "+us:0,1");
+  EXPECT_EQ(schema.n_children, 2);
+  
+  arrow_type = ImportType(&schema);
+  ARROW_EXPECT_OK(arrow_type);
+  EXPECT_TRUE(arrow_type.ValueUnsafe()->Equals(sparse_union({field("u1", int32()), field("u2", utf8())})));
+
+  ArrowSchemaInit(&schema);
+  EXPECT_EQ(ArrowSchemaSetTypeUnion(&schema, NANOARROW_TYPE_DENSE_UNION, 2), NANOARROW_OK);
+  EXPECT_EQ(ArrowSchemaSetName(schema.children[0], "u1"), NANOARROW_OK);
+  EXPECT_EQ(ArrowSchemaSetType(schema.children[0], NANOARROW_TYPE_INT32), NANOARROW_OK);
+  EXPECT_EQ(ArrowSchemaSetName(schema.children[1], "u2"), NANOARROW_OK);
+  EXPECT_EQ(ArrowSchemaSetType(schema.children[1], NANOARROW_TYPE_STRING), NANOARROW_OK);
+  EXPECT_STREQ(schema.format, "+ud:0,1");
+  EXPECT_EQ(schema.n_children, 2);
+  
+  arrow_type = ImportType(&schema);
+  ARROW_EXPECT_OK(arrow_type);
+  EXPECT_TRUE(arrow_type.ValueUnsafe()->Equals(dense_union({field("u1", int32()), field("u2", utf8())})));
+}
+
 TEST(SchemaTest, SchemaSetFormat) {
   struct ArrowSchema schema;
-  ArrowSchemaInit(&schema, NANOARROW_TYPE_UNINITIALIZED);
+  ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_UNINITIALIZED);
 
   EXPECT_EQ(ArrowSchemaSetFormat(&schema, "i"), NANOARROW_OK);
   EXPECT_STREQ(schema.format, "i");
@@ -322,7 +373,7 @@ TEST(SchemaTest, SchemaSetFormat) {
 
 TEST(SchemaTest, SchemaSetName) {
   struct ArrowSchema schema;
-  ArrowSchemaInit(&schema, NANOARROW_TYPE_UNINITIALIZED);
+  ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_UNINITIALIZED);
 
   EXPECT_EQ(ArrowSchemaSetName(&schema, "a_name"), NANOARROW_OK);
   EXPECT_STREQ(schema.name, "a_name");
@@ -335,7 +386,7 @@ TEST(SchemaTest, SchemaSetName) {
 
 TEST(SchemaTest, SchemaSetMetadata) {
   struct ArrowSchema schema;
-  ArrowSchemaInit(&schema, NANOARROW_TYPE_UNINITIALIZED);
+  ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_UNINITIALIZED);
 
   // (test will only work on little endian)
   char simple_metadata[] = {'\1', '\0', '\0', '\0', '\3', '\0', '\0', '\0', 'k', 'e',
@@ -352,7 +403,7 @@ TEST(SchemaTest, SchemaSetMetadata) {
 
 TEST(SchemaTest, SchemaAllocateDictionary) {
   struct ArrowSchema schema;
-  ArrowSchemaInit(&schema, NANOARROW_TYPE_UNINITIALIZED);
+  ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_UNINITIALIZED);
 
   EXPECT_EQ(ArrowSchemaAllocateDictionary(&schema), NANOARROW_OK);
   EXPECT_EQ(schema.dictionary->release, nullptr);
@@ -460,7 +511,7 @@ TEST(SchemaViewTest, SchemaViewInitErrors) {
   EXPECT_EQ(ArrowSchemaViewInit(&schema_view, &schema, &error), EINVAL);
   EXPECT_STREQ(ArrowErrorMessage(&error), "Expected non-released schema");
 
-  ASSERT_EQ(ArrowSchemaInit(&schema, NANOARROW_TYPE_UNINITIALIZED), NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_UNINITIALIZED), NANOARROW_OK);
   EXPECT_EQ(ArrowSchemaViewInit(&schema_view, &schema, &error), EINVAL);
   EXPECT_STREQ(
       ArrowErrorMessage(&error),
@@ -539,7 +590,7 @@ TEST(SchemaViewTest, SchemaViewInitSimpleErrors) {
   struct ArrowSchemaView schema_view;
   struct ArrowError error;
 
-  ASSERT_EQ(ArrowSchemaInit(&schema, NANOARROW_TYPE_NA), NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_NA), NANOARROW_OK);
   ASSERT_EQ(ArrowSchemaAllocateChildren(&schema, 2), NANOARROW_OK);
   EXPECT_EQ(ArrowSchemaViewInit(&schema_view, &schema, &error), EINVAL);
   EXPECT_STREQ(ArrowErrorMessage(&error),
@@ -590,7 +641,7 @@ TEST(SchemaViewTest, SchemaViewInitDecimalErrors) {
   struct ArrowSchema schema;
   struct ArrowSchemaView schema_view;
   struct ArrowError error;
-  ASSERT_EQ(ArrowSchemaInit(&schema, NANOARROW_TYPE_NA), NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_NA), NANOARROW_OK);
 
   ASSERT_EQ(ArrowSchemaSetFormat(&schema, "d"), NANOARROW_OK);
   EXPECT_EQ(ArrowSchemaViewInit(&schema_view, &schema, &error), EINVAL);
@@ -707,7 +758,7 @@ TEST(SchemaViewTest, SchemaViewInitBinaryAndStringErrors) {
   struct ArrowSchema schema;
   struct ArrowSchemaView schema_view;
   struct ArrowError error;
-  ASSERT_EQ(ArrowSchemaInit(&schema, NANOARROW_TYPE_NA), NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_NA), NANOARROW_OK);
 
   ASSERT_EQ(ArrowSchemaSetFormat(&schema, "w"), NANOARROW_OK);
   EXPECT_EQ(ArrowSchemaViewInit(&schema_view, &schema, &error), EINVAL);
@@ -897,7 +948,7 @@ TEST(SchemaViewTest, SchemaViewInitTimeErrors) {
   struct ArrowSchema schema;
   struct ArrowSchemaView schema_view;
   struct ArrowError error;
-  ASSERT_EQ(ArrowSchemaInit(&schema, NANOARROW_TYPE_NA), NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_NA), NANOARROW_OK);
 
   ASSERT_EQ(ArrowSchemaSetFormat(&schema, "t*"), NANOARROW_OK);
   EXPECT_EQ(ArrowSchemaViewInit(&schema_view, &schema, &error), EINVAL);
@@ -994,7 +1045,7 @@ TEST(SchemaViewTest, SchemaViewNestedListErrors) {
   struct ArrowSchema schema;
   struct ArrowSchemaView schema_view;
   struct ArrowError error;
-  ASSERT_EQ(ArrowSchemaInit(&schema, NANOARROW_TYPE_NA), NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_NA), NANOARROW_OK);
 
   ASSERT_EQ(ArrowSchemaSetFormat(&schema, "+w"), NANOARROW_OK);
   EXPECT_EQ(ArrowSchemaViewInit(&schema_view, &schema, &error), EINVAL);
@@ -1044,7 +1095,7 @@ TEST(SchemaViewTest, SchemaViewInitNestedStructErrors) {
   struct ArrowSchemaView schema_view;
   struct ArrowError error;
 
-  ASSERT_EQ(ArrowSchemaInit(&schema, NANOARROW_TYPE_STRUCT), NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_STRUCT), NANOARROW_OK);
   ASSERT_EQ(ArrowSchemaAllocateChildren(&schema, 1), NANOARROW_OK);
   EXPECT_EQ(ArrowSchemaViewInit(&schema_view, &schema, &error), EINVAL);
   EXPECT_STREQ(
@@ -1052,7 +1103,7 @@ TEST(SchemaViewTest, SchemaViewInitNestedStructErrors) {
       "Expected valid schema at schema->children[0] but found a released schema");
 
   // Make sure validation passes even with an inspectable but invalid child
-  ASSERT_EQ(ArrowSchemaInit(schema.children[0], NANOARROW_TYPE_UNINITIALIZED),
+  ASSERT_EQ(ArrowSchemaInitFromType(schema.children[0], NANOARROW_TYPE_UNINITIALIZED),
             NANOARROW_OK);
   EXPECT_EQ(ArrowSchemaViewInit(&schema_view, schema.children[0], &error), EINVAL);
   EXPECT_EQ(ArrowSchemaViewInit(&schema_view, &schema, &error), NANOARROW_OK);
@@ -1089,16 +1140,18 @@ TEST(SchemaViewTest, SchemaViewInitNestedMapErrors) {
   struct ArrowSchemaView schema_view;
   struct ArrowError error;
 
-  ASSERT_EQ(ArrowSchemaInit(&schema, NANOARROW_TYPE_MAP), NANOARROW_OK);
+  ArrowSchemaInit(&schema);
+  ASSERT_EQ(ArrowSchemaSetFormat(&schema, "+m"), NANOARROW_OK);
   ASSERT_EQ(ArrowSchemaAllocateChildren(&schema, 2), NANOARROW_OK);
   EXPECT_EQ(ArrowSchemaViewInit(&schema_view, &schema, &error), EINVAL);
   EXPECT_STREQ(ArrowErrorMessage(&error),
                "Expected schema with 1 children but found 2 children");
   schema.release(&schema);
 
-  ASSERT_EQ(ArrowSchemaInit(&schema, NANOARROW_TYPE_MAP), NANOARROW_OK);
+  ArrowSchemaInit(&schema);
+  ASSERT_EQ(ArrowSchemaSetFormat(&schema, "+m"), NANOARROW_OK);
   ASSERT_EQ(ArrowSchemaAllocateChildren(&schema, 1), NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaInit(schema.children[0], NANOARROW_TYPE_UNINITIALIZED),
+  ASSERT_EQ(ArrowSchemaInitFromType(schema.children[0], NANOARROW_TYPE_UNINITIALIZED),
             NANOARROW_OK);
   ASSERT_EQ(ArrowSchemaSetFormat(schema.children[0], "n"), NANOARROW_OK);
   EXPECT_EQ(ArrowSchemaViewInit(&schema_view, &schema, &error), EINVAL);
@@ -1106,15 +1159,16 @@ TEST(SchemaViewTest, SchemaViewInitNestedMapErrors) {
                "Expected child of map type to have 2 children but found 0");
   schema.release(&schema);
 
-  ASSERT_EQ(ArrowSchemaInit(&schema, NANOARROW_TYPE_MAP), NANOARROW_OK);
+  ArrowSchemaInit(&schema);
+  ASSERT_EQ(ArrowSchemaSetFormat(&schema, "+m"), NANOARROW_OK);
   ASSERT_EQ(ArrowSchemaAllocateChildren(&schema, 1), NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaInit(schema.children[0], NANOARROW_TYPE_UNINITIALIZED),
+  ASSERT_EQ(ArrowSchemaInitFromType(schema.children[0], NANOARROW_TYPE_UNINITIALIZED),
             NANOARROW_OK);
   ASSERT_EQ(ArrowSchemaAllocateChildren(schema.children[0], 2), NANOARROW_OK);
   ASSERT_EQ(ArrowSchemaSetFormat(schema.children[0], "+us:0,1"), NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaInit(schema.children[0]->children[0], NANOARROW_TYPE_NA),
+  ASSERT_EQ(ArrowSchemaInitFromType(schema.children[0]->children[0], NANOARROW_TYPE_NA),
             NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaInit(schema.children[0]->children[1], NANOARROW_TYPE_NA),
+  ASSERT_EQ(ArrowSchemaInitFromType(schema.children[0]->children[1], NANOARROW_TYPE_NA),
             NANOARROW_OK);
 
   EXPECT_EQ(ArrowSchemaViewInit(&schema_view, &schema, &error), EINVAL);
@@ -1165,7 +1219,7 @@ TEST(SchemaViewTest, SchemaViewInitNestedUnionErrors) {
   struct ArrowSchema schema;
   struct ArrowSchemaView schema_view;
   struct ArrowError error;
-  ASSERT_EQ(ArrowSchemaInit(&schema, NANOARROW_TYPE_NA), NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_NA), NANOARROW_OK);
 
   ASSERT_EQ(ArrowSchemaSetFormat(&schema, "+u*"), NANOARROW_OK);
   EXPECT_EQ(ArrowSchemaViewInit(&schema_view, &schema, &error), EINVAL);
@@ -1187,7 +1241,7 @@ TEST(SchemaViewTest, SchemaViewInitInvalidSpecErrors) {
   struct ArrowSchema schema;
   struct ArrowSchemaView schema_view;
   struct ArrowError error;
-  ASSERT_EQ(ArrowSchemaInit(&schema, NANOARROW_TYPE_NA), NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_NA), NANOARROW_OK);
 
   ASSERT_EQ(ArrowSchemaSetFormat(&schema, "+Z"), NANOARROW_OK);
   EXPECT_EQ(ArrowSchemaViewInit(&schema_view, &schema, &error), EINVAL);
@@ -1216,15 +1270,16 @@ TEST(SchemaViewTest, SchemaViewInitDictionaryErrors) {
   struct ArrowSchemaView schema_view;
   struct ArrowError error;
 
-  ASSERT_EQ(ArrowSchemaInit(&schema, NANOARROW_TYPE_INT32), NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_INT32), NANOARROW_OK);
   ASSERT_EQ(ArrowSchemaAllocateDictionary(&schema), NANOARROW_OK);
   EXPECT_EQ(ArrowSchemaViewInit(&schema_view, &schema, &error), EINVAL);
   EXPECT_STREQ(ArrowErrorMessage(&error), "Expected non-released schema");
   schema.release(&schema);
 
-  ASSERT_EQ(ArrowSchemaInit(&schema, NANOARROW_TYPE_STRUCT), NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_STRUCT), NANOARROW_OK);
   ASSERT_EQ(ArrowSchemaAllocateDictionary(&schema), NANOARROW_OK);
-  ASSERT_EQ(ArrowSchemaInit(schema.dictionary, NANOARROW_TYPE_STRING), NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaInitFromType(schema.dictionary, NANOARROW_TYPE_STRING),
+            NANOARROW_OK);
   EXPECT_EQ(ArrowSchemaViewInit(&schema_view, &schema, &error), EINVAL);
   EXPECT_STREQ(
       ArrowErrorMessage(&error),
@@ -1305,7 +1360,7 @@ TEST(SchemaViewTest, SchemaFormatInvalid) {
   schema.release = nullptr;
   EXPECT_EQ(ArrowSchemaToStdString(&schema), "[invalid: schema is released]");
 
-  ASSERT_EQ(ArrowSchemaInit(&schema, NANOARROW_TYPE_UNINITIALIZED), NANOARROW_OK);
+  ASSERT_EQ(ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_UNINITIALIZED), NANOARROW_OK);
   EXPECT_EQ(ArrowSchemaToStdString(&schema),
             "[invalid: Error parsing schema->format: Expected a null-terminated string "
             "but found NULL]");