Kartik Agaram
Walker Griggs
11/24/2023, 6:16 PMshalabh
11/24/2023, 6:35 PMFor a start, you can actually find the code as a single artifact rather than it being the product of a log of mutations.Some of this gets lost even in dead-langs when you’re dealing with macros, metaprogramming or subsclassing at some level of complexity. Not only do you have to simulate the runtime semantics in your head, you also have to simulate the type checker and compiler semantics.
Justin Blank
11/24/2023, 6:44 PMKartik Agaram
I believe the issues described with live systems are not actually solved with dead systems, but just deferred until later. That’s because dead systems don’t often represent entire systems but only a slice of the system.. upgrading [a] downstream service may change or delete an API method and it leave it incompatible with the caller.This depends on the context. If you think of the upstream and downstream as within a common ownership boundary, then such checks are valuable. However, if they span ownership boundaries then these checks can seem onerous. You're right that dead systems work almost accidentally for the second case, by just not doing some work. Ideally we'd have both tools in our pocket, and the flexibility to select from them depending on the situation. However, this is a lot of complexity, and all code carries costs. So worse may be better here. This situation is analogous to structured editing like in @alltom's recent submission https://futureofcoding.slack.com/archives/C5T9GPWFL/p1700405882617679. It's easy for a structured editor to feel like an overbearing presence. The implementor has to juggle both technical complexity and UX nuance. Meanwhile plain text is often "good enough" and so we continue to muddle along..
shalabh
11/24/2023, 7:45 PMIt’s possible to do monitoring in your runtime.Yeah, the key requirement is version-awareness - whether the endpoint name encodes the version or some introspection api returns the version of the service, any strategy needs a representation of the version of functions etc within the system itself, and should allow multiple versions to coexist. An interesting implementation here is gemstone smalltalk - it is a live system where you can evolve the schema by providing migration methods and the objects can be migrated to newer definitions either opportunistically or in batch.
Kartik Agaram
shalabh
11/24/2023, 8:11 PMshalabh
11/24/2023, 8:19 PMKartik Agaram
Duncan Cragg
11/25/2023, 10:34 AMKonrad Hinsen
11/25/2023, 5:01 PMDynamic programming languages face semantic and performance challenges in the presence of features, such
as eval, that can inject new code into a running program. The Julia programming language introduces the
novel concept of world age to insulate optimized code from one of the most disruptive side-effects of eval:
changes to the definition of an existing function. This paper provides the first formal semantics of world age
in a core calculus named Juliette, and shows how world age enables compiler optimizations, such as inlining,
in the presence of eval. While Julia also provides programmers with the means to bypass world age, we found
that this mechanism is not used extensively: a static analysis of over 4,000 registered Julia packages shows
that only 4–9% of packages bypass world age. This suggests that Julia’s semantics aligns with programmer
expectations.
jamii
11/26/2023, 12:31 AMjulia> foo(x, y) = x + y
foo (generic function with 1 method)
julia> bar = x -> foo(x, 1)
#3 (generic function with 1 method)
julia> bar(1)
2
julia> @code_llvm bar(1)
; @ REPL[1]:1 within `#3`
define i64 @"julia_#3_122"(i64 signext %0) #0 {
top:
; ┌ @ REPL[7]:1 within `foo`
; │┌ @ int.jl:87 within `+`
%1 = add i64 %0, 1
; └└
ret i64 %1
}
julia> Base.delete_method(@which foo(1,1))
julia> bar(1)
ERROR: MethodError: no method matching foo(::Int64, ::Int64)
Stacktrace:
[1] (::var"#3#4")(x::Int64)
@ Main ./REPL[1]:1
[2] top-level scope
@ REPL[6]:1
julia> @code_llvm bar(1)
; @ REPL[1]:1 within `#3`
; Function Attrs: noreturn
define void @"julia_#3_133"(i64 signext %0) #0 {
top:
%1 = alloca [2 x {}*], align 8
%gcframe2 = alloca [3 x {}*], align 16
%gcframe2.sub = getelementptr inbounds [3 x {}*], [3 x {}*]* %gcframe2, i64 0, i64 0
%.sub = getelementptr inbounds [2 x {}*], [2 x {}*]* %1, i64 0, i64 0
%2 = bitcast [3 x {}*]* %gcframe2 to i8*
call void @llvm.memset.p0i8.i32(i8* noundef nonnull align 16 dereferenceable(24) %2, i8 0, i32 24, i1 false)
%thread_ptr = call i8* asm "movq %fs:0, $0", "=r"() #6
%ppgcstack_i8 = getelementptr i8, i8* %thread_ptr, i64 -8
%ppgcstack = bitcast i8* %ppgcstack_i8 to {}****
%pgcstack = load {}***, {}**** %ppgcstack, align 8
%3 = bitcast [3 x {}*]* %gcframe2 to i64*
store i64 4, i64* %3, align 16
%4 = getelementptr inbounds [3 x {}*], [3 x {}*]* %gcframe2, i64 0, i64 1
%5 = bitcast {}** %4 to {}***
%6 = load {}**, {}*** %pgcstack, align 8
store {}** %6, {}*** %5, align 8
%7 = bitcast {}*** %pgcstack to {}***
store {}** %gcframe2.sub, {}*** %7, align 8
%8 = call nonnull {}* @ijl_box_int64(i64 signext %0)
%9 = getelementptr inbounds [3 x {}*], [3 x {}*]* %gcframe2, i64 0, i64 2
store {}* %8, {}** %9, align 16
store {}* %8, {}** %.sub, align 8
%10 = getelementptr inbounds [2 x {}*], [2 x {}*]* %1, i64 0, i64 1
store {}* inttoptr (i64 140053833609312 to {}*), {}** %10, align 8
%11 = call nonnull {}* @ijl_apply_generic({}* inttoptr (i64 140053835183152 to {}*), {}** nonnull %.sub, i32 2)
call void @llvm.trap()
unreachable
}
Konrad Hinsen
11/26/2023, 10:52 AMjonathoda
11/26/2023, 6:59 PMjonathoda
11/26/2023, 8:34 PMBeni Cherniavsky-Paskin
12/02/2023, 6:42 PMMattia Fregola
12/04/2023, 3:21 AMShubhadeep Roychowdhury
12/04/2023, 12:27 PMJimmy Miller
Shubhadeep Roychowdhury
12/05/2023, 4:00 AMAlex McLean
12/05/2023, 12:29 PM