# Discussion Towards: Incremental Coding/ Native Query Language in Julia

**URL:** <https://discourse.julialang.org/t/discussion-towards-incremental-coding-native-query-language-in-julia/125873>\
**Category:** General Usage\
**Created:** [February 13, 2025, 6:05pm UTC](https://discourse.julialang.org/t/discussion-towards-incremental-coding-native-query-language-in-julia/125873 "2025-02-13T18:05:27Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![GeekyPeas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/geekypeas/32/38705_2.png) [@GeekyPeas](https://discourse.julialang.org/u/GeekyPeas)\
**Post date:** [February 13, 2025, 6:05pm UTC](https://discourse.julialang.org/t/discussion-towards-incremental-coding-native-query-language-in-julia/125873/1 "2025-02-13T18:05:27Z")

</div>

**WARNING:** Visionary/ Feeling inspired. Call for advice, suggestions on how to proceed.

# Summary

I imagine to be able to declare only the type of a variable and not assign it any value. This might be useful as It can act as `typed hole`, a placeholder of sorts, that still would allow some forms of type checking, code generation, pattern matching, meta programming, linting, syntax highlighting, IDE support etc.

> **TL;DR** Given some type `T`, I want to be able to do `x = @var(T)` inside some _limited_ context/ scope where it maybe useful to let it behave as if `x` were a term of type `T`.

**EDIT** : The above has been _partially_ solved [here](https://discourse.julialang.org/t/discussion-towards-incremental-coding-native-query-language-in-julia/125873/2). Opens discussions to other things below:

# Intention for Useage

These are some ways I imagine wanting to use this:

1. For incremental coding (inspired by [Hazel](https://hazel.org/)):

```julia
@unfinished_code begin
x=@var(T) where Int<:T<:Real
y=x+2
end

```

1. Using Julia _natively_ as a query language:

I am aware that there are Julia ORMs. But to be able to express the constraints/ pattern of a query in Julia _natively_ might open unexpected applications (as, database need not be the only target for such a query: for example [Trustfall](https://github.com/obi1kenobi/trustfall)).

I am imagining something like these:

```julia
pattern = @search_pattern begin
s = @var(student)
1 <= s.studentID <= 5 || s.studentID = 5 || occursin(r'%Maximo', s.FullName)
s.sat_score > 1400 || s.sat_score < 1000
end

results = source.match(pattern)

```

instead of:

```sql
select studentID, FullName, sat_score, recordUpdated
from student
where
  (
    studentID between 1 and 5
    or studentID = 8
    or FullName like '%Maximo%'
  )
and sat_score NOT in (1000, 1400);

```

in `sql`, or maybe something like this:

```julia
 search_pattern = @pattern begin
 (r, tom, m) = @var(T, Person, Movie) where T<:relationship
 tom.name = 'Tom Hanks'
 r = T(tom,m)
 end

 results = source.match(search_pattern).collect(typeof(r), m.title)

```

instead of:

```cypher
MATCH (tom:Person {name:'Tom Hanks'})-[r]->(m:Movie)
RETURN type(r) AS type, m.title AS movie

```

in `cypher` in `Neo4j`, or

```julia
  search_pattern = @pattern begin
      u, obj, act = @var(user, object, action)
      u.name='Kevin Morrison'
      obj.path='path'
      act.name = 'modify_file'
      permission(u,access(obj,act))
  end

  results = source.match(search_pattern).collect(obj.path)

```

instead of:

```julia-auto
match
$user isa user, has full-name 'Kevin Morrison';
($user, $access) isa permission;
$obj isa object, has path $path;
$access($obj, $act) isa access;
$act isa action, has name 'modify_file';
fetch $path;

```

in `typeql` from `typedb`.

# Conclusion

_Yes_, this is asking for a lot of syntactic sugar. And I don’t know if this is even possible. But I hope to open a discussion towards the right kind of syntactic sugar that is useful and possible.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [February 13, 2025, 6:14pm UTC](https://discourse.julialang.org/t/discussion-towards-incremental-coding-native-query-language-in-julia/125873/2 "2025-02-13T18:14:46Z")

</div>

> [@GeekyPeas](#):
>
> I imagine to be able to declare only the type of a variable and not assign it any value.

Variables indeed can have declared types without assigned values. Access without a value errors, and so does assignment of values that can’t be converted to the declared type. Note that the `local`/`global` keywords are necessary because `x::Int` already means type assertion of the instance assigned to a variable.

```julia
julia> module TypedDemo
         global x::Int
         function foo(z)
           local y::Int
           y = z
         end
       end
Main.TypedDemo

julia> TypedDemo.x
ERROR: UndefVarError: `x` not defined in `Main.TypedDemo`
Suggestion: add an appropriate import or assignment. This global was declared but not assigned.
Stacktrace:
...

julia> TypedDemo.x = "one"
ERROR: MethodError: Cannot `convert` an object of type String to an object of type Int64
...

julia> TypedDemo.foo("one")
ERROR: MethodError: Cannot `convert` an object of type String to an object of type Int64
...

```

That alone doesn’t come close to the things discussed here, but maybe it can be useful.

---

<div class="post-metadata">

**Author:** ![GeekyPeas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/geekypeas/32/38705_2.png) [@GeekyPeas](https://discourse.julialang.org/u/GeekyPeas)\
**Post date:** [February 13, 2025, 6:34pm UTC](https://discourse.julialang.org/t/discussion-towards-incremental-coding-native-query-language-in-julia/125873/4 "2025-02-13T18:34:50Z")

</div>

@Benny Ah this was easier than I was thinking. Yes it solves my main question. But I will wait for discussion on the other things.

I have EDIT-ed the title of the post to reflect the focus of the question.

But, thank you so much!

---

<div class="post-metadata">

**Author:** ![GeekyPeas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/geekypeas/32/38705_2.png) [@GeekyPeas](https://discourse.julialang.org/u/GeekyPeas)\
**Post date:** [February 13, 2025, 6:48pm UTC](https://discourse.julialang.org/t/discussion-towards-incremental-coding-native-query-language-in-julia/125873/5 "2025-02-13T18:48:57Z")

</div>

So suppose I have a `struct` like:

```julia
struct Person
    name::String
    age::Int
end

```

Yes I can do `global x::Person`. But I can’t do `x.name = "Harry"` or `global x.name = "Harry"`.

But maybe I could try creating the `@var: struct --> struct` macro that would create a new type that is `mutable` with the same attribute names but now with type `Union(orginial_type, nothing)` and initialize this type with `nothing`. This could allow rewriting with `x.name = "Harry"`. Your thoughts?

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [February 13, 2025, 7:02pm UTC](https://discourse.julialang.org/t/discussion-towards-incremental-coding-native-query-language-in-julia/125873/6 "2025-02-13T19:02:11Z")

</div>

> [@GeekyPeas](#):
>
> But I can’t do `x.name = "Harry"` or `global x.name = "Harry"`.

Not for `struct` definitions alone because you’re only specifying the field structure there, too early to designate any particular values. Assigning values occurs in constructor methods that perform _instantiation_. However, `@kwdef struct` does support that syntax to be transformed into constructor method arguments with default values.

---

<div class="post-metadata">

**Author:** ![GeekyPeas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/geekypeas/32/38705_2.png) [@GeekyPeas](https://discourse.julialang.org/u/GeekyPeas)\
**Post date:** [February 13, 2025, 8:38pm UTC](https://discourse.julialang.org/t/discussion-towards-incremental-coding-native-query-language-in-julia/125873/7 "2025-02-13T20:38:07Z")

</div>

Thanks @Benny for `@kwdef`.

Here is my top-level idea:

1. @var macro takes in a type `T` and creates an instance of type `duck_T`. This new type `duck_T` has _almost_ the same structure as `T` except depending on some `context` it is initialized to `nothing` or `any`.

2. There will be a macro called `@allow_duck_typing`. It creates a siloed environment inside which the types `T` and `duck_T` will be indistinguishable. I have not thought through fully how to implement this. But I am thinking to do `duck_T <: __ducks__ ` where `abstract type __ducks__ end`. And then to do function over-ridding:

```julia
#feels controversial; what does it solve and _not_ solve?
Base.typeof(x::Duck_T) = T 

```

**Question:** Will traits be useful/ better here?

1. Then `@search_pattern` sets `context` to `any`, as the end problem is a constraint satisfying problem (CSP). The actual lines of Julia inside this macro are irrelevant at run-time. They only have “meaning” at compile-time. And the “meaning” is to compile the code into an unified IR or AST capable of representing any CSP problem (like in SMT). Then depending on the type of the `target` where this CSP will be run against, the actual executable can be multiple-dispatched. The `target` can be different types of databases or even filesystems or APIs (like in Trustfall). This will be like the same code in Julia compiling against different hardwares (GPU/ CPU etc).

Porting the pattern to a SMT format can be useful: a SMT-solver maybe used to “simplify” the constraints and come up with an optimized query plan.

**Question:** maybe using a macro is an overkill. Looks like what I have described can be done with a function. I haven’t read enough from Julia to know what is better. Please advice.

1. For the `@unfinished_code`, I would set the `context` to `none`, to make a more conservative guess. But I haven’t thought far.

2. So intended use is something like this:

```julia
@allow_duck_typing begin

pattern = @search_pattern begin

# rest of code ...

end 

end
```
