From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp2.migadu.com ([2001:41d0:303:e224::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms5.migadu.com with LMTPS id WDxPJtgGE2b0UQAAe85BDQ:P1 (envelope-from ) for ; Sun, 07 Apr 2024 22:49:28 +0200 Received: from aspmx1.migadu.com ([2001:41d0:303:e224::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp2.migadu.com with LMTPS id WDxPJtgGE2b0UQAAe85BDQ (envelope-from ) for ; Sun, 07 Apr 2024 22:49:28 +0200 X-Envelope-To: patches@johnnyrichard.com Authentication-Results: aspmx1.migadu.com; none Received: from mail-a.sr.ht (mail-a.sr.ht [46.23.81.152]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id 935E22676A for ; Sun, 7 Apr 2024 22:49:25 +0200 (CEST) DKIM-Signature: a=rsa-sha256; bh=5t4DB5u+qqOnu2eFCtRlK/pWCvEcsFojYAK71gjLFAk=; c=simple/simple; d=lists.sr.ht; h=Date:Cc:Subject:From:To:References:In-Reply-To:List-Unsubscribe:List-Subscribe:List-Archive:List-Post:List-ID; q=dns/txt; s=20240113; t=1712522965; v=1; b=WbNKUxYfIaKIg0Hq9HritkbVxCggFvv4Yw+7LkfUggMTU6JYh/6cVcr1XSQlYX+6yzois/8k e4y2MqKyeWUSq3VTiYXFeFPdsBnSekJHBh/uHxOhHCVfaOptlDJmHLuuGYynPW4X8fR3MAFYTdc 27J8rPsEHneeADEdbtzQ/kLs5IxVShSC3YRSLdIwOP97umtK4G+IPoaSgksmV2md4GZ5ECMDfIM MjkyZRQVCU9oz+jkZgxV6POupqsOzcNwRTXXmey+EZwCzeQmMFbxArngZVdZRVTYQ4ckeQY59+X wed4j0ODfp0igBh5IN9ICwo05SlskWcu35YkY56lzO+uQ== Received: from lists.sr.ht (unknown [46.23.81.154]) by mail-a.sr.ht (Postfix) with ESMTPSA id F3817201C6 for ; Sun, 7 Apr 2024 20:49:24 +0000 (UTC) Received: from black.elm.relay.mailchannels.net (black.elm.relay.mailchannels.net [23.83.212.19]) by mail-a.sr.ht (Postfix) with ESMTPS id CBC6920191 for <~johnnyrichard/olang-devel@lists.sr.ht>; Sun, 7 Apr 2024 20:49:23 +0000 (UTC) X-Sender-Id: hostingeremail|x-authuser|carlos@maniero.me Received: from relay.mailchannels.net (localhost [127.0.0.1]) by relay.mailchannels.net (Postfix) with ESMTP id 357D9C1425 for <~johnnyrichard/olang-devel@lists.sr.ht>; Sun, 7 Apr 2024 20:49:22 +0000 (UTC) Received: from fr-int-smtpout1.hostinger.io (unknown [127.0.0.6]) (Authenticated sender: hostingeremail) by relay.mailchannels.net (Postfix) with ESMTPA id 56F58C1F3F for <~johnnyrichard/olang-devel@lists.sr.ht>; Sun, 7 Apr 2024 20:49:21 +0000 (UTC) ARC-Seal: i=1; s=arc-2022; d=mailchannels.net; t=1712522961; a=rsa-sha256; cv=none; b=kfre68qYRez6Ph6jgMiCRZtAQoyytrVgB811uosEZgUrBfp05wRwh9SdNVhBdYqa2uBZFz KJ2Q0f1k8gcnbMQgrANUe9eSYYjYgWb9w3k9pOIm++oapf3ebdRDL0Z4BO5JS3Lu3a/F9o IEhoV1LnDfPcDkDmP/n/yWFY4bHhAhvqBMSwT7hOuKFgPjfxhkGfKhM4oUDQ7TwpPwkEVB 4c3lbsnnIbQY2qgxwjJihN782RsY2Z0KPhfD2YicX0a6PPg3urevdQ5Sa3iOIWvWEbjZsg eUC11cpaZXlvruXACX6n4uljlVaPUUCFG6f8UyNGSwtoyfdF/4bhc5qlGUUQZQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=mailchannels.net; s=arc-2022; t=1712522961; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=qCRUzCWkLwKfeynckfLOEF+Y62o0OxJ3fwbTFsFzJmU=; b=ikU0fA3yUpTTFFEeX3vkMJBkd8fwRTRsBuQQUNE8PatHNFLK8jHlDg8wZMU3vbvvM2xmb5 GJIYEDiBfXEEUKe64RJkY7h3bX35njXoX+QLOIz8bqG8tQx2sPcfd+XOTTKtmas6B91C1x beDiZf6N2S3x5/J5wRpdjbudlcHmCxPOjslJ54b3IzC2HJ4FjUg5ZMzVv/YljE+9dxivfA Dqau5pqE87n3RjI5A+66/gy4CG30TtDYC4/p8meej3cq32yZ8WB9qlZ/5tbyeGjB1c/jXg YwiWx/VWPNxzhXLfaAHcdiCCMMmQS8a7PKuEv/55wlLPrh2DUfDofR3VD8mwbw== ARC-Authentication-Results: i=1; rspamd-687b9dd446-x47zz; auth=pass smtp.auth=hostingeremail smtp.mailfrom=carlos@maniero.me X-Sender-Id: hostingeremail|x-authuser|carlos@maniero.me X-MC-Relay: Neutral X-MailChannels-SenderId: hostingeremail|x-authuser|carlos@maniero.me X-MailChannels-Auth-Id: hostingeremail X-Tasty-Relation: 1a7278285c26e60d_1712522962053_3868793227 X-MC-Loop-Signature: 1712522962053:2851822087 X-MC-Ingress-Time: 1712522962052 Received: from fr-int-smtpout1.hostinger.io (fr-int-smtpout1.hostinger.io [89.116.146.80]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384) by 100.117.22.138 (trex/6.9.2); Sun, 07 Apr 2024 20:49:22 +0000 Mime-Version: 1.0 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=maniero.me; s=hostingermail1; t=1712522959; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=qCRUzCWkLwKfeynckfLOEF+Y62o0OxJ3fwbTFsFzJmU=; b=UfFZfChSS8Oes39Vlok7q7VwqZKS+T53VD8xFpteOBP91I7ER7+6sfK6xWxPgXgDX7hda6 P+nupH/k9P4DvaLWzA9w+XPX/UZHChqGw2POOQ1z6YFfTlEEVrbenglJ6KKe9mv71JtDgQ 2WQ+ww39KCAumsq5/XmX7gqy9NdgC0YFkxlKOYS92ESFo3lxVmFzYq3UC7y64J3wnRX0Gh MXOfBDPgVp2jrj2NNms8/rLj1HPNxE7f11KtL29qzX1br3ROe4jBrEoTefj2WI0Ll01H4r Uiszuw/4nm7K+mtn9HZqS0Ts+QzU0Hqq0EqF/bln/mH1T2df5K6DHTPY6ddDJw== Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=UTF-8 Date: Sun, 07 Apr 2024 17:49:14 -0300 Message-Id: Cc: <~johnnyrichard/olang-devel@lists.sr.ht> Subject: Re: [RFC] Namespaces in OLANG From: "Carlos Maniero" To: "Johnny Richard" X-Mailer: aerc 0.15.2-211-g37d5fc691aff References: In-Reply-To: X-CM-Envelope: MS4xfKTepdi5zpnbAn3qZ90xzilS2aMS0qh5UYh4VyBAi5hysubw9qXPxngHUEAVxrgiLoxW/8citU3O69mOuS7gce/6+6Jho7v5NOzRoE4KRZY/v6CpqP1X 6MAdvvV1zsrfPCW8vbkQDXOXUB33jhYJOVe5lkNEiiK3jjpszaDH6Y3Tppi9PZx4Wmmeum92dvvyleKTaeLwiRcd7VSmwqvE9fIc49ZKxmQAvXQLUCNyFU9r ciXqtXUwtdW/bsgG3QP+Zg== X-CM-Analysis: v=2.4 cv=ZKfRm27b c=1 sm=1 tr=0 ts=661306cf a=WwxFCuf3mf1fs3oSi6/dng==:117 a=WwxFCuf3mf1fs3oSi6/dng==:17 a=IkcTkHD0fZMA:10 a=MKtGQD3n3ToA:10 a=1oJP67jkp3AA:10 a=NEAV23lmAAAA:8 a=uPZiAMpXAAAA:8 a=QOUOMCz4AAAA:8 a=3DW5ysfuAAAA:8 a=6nd9erHWJ5cFb8S0kmIA:9 a=QEXdDO2ut3YA:10 a=nIi5PErmxZUA:10 a=BXDaF_L80NY05PYiAFlV:22 a=_uwhyy-cTs3PKpKTLvtj:22 a=fr250BOHKi_Lf9mVLe9j:22 X-AuthUser: carlos@maniero.me List-Unsubscribe: List-Subscribe: List-Archive: Archived-At: List-Post: List-ID: ~johnnyrichard/olang-devel <~johnnyrichard/olang-devel.lists.sr.ht> Sender: ~johnnyrichard/olang-devel <~johnnyrichard/olang-devel@lists.sr.ht> X-Migadu-Flow: FLOW_IN X-Migadu-Country: NL X-Migadu-Spam-Score: -4.00 X-Spam-Score: -4.00 X-Migadu-Queue-Id: 935E22676A X-Migadu-Scanner: mx12.migadu.com X-TUID: ZPIO09PvAH+n I confess that this is my last attempt to explain what I'm suggesting. I believe neither you and me have energy to continue discussing this subject. So if you don't get it I believe we could just drop it. > > > > - It simplifies the resolution of imports. > > > > > > I would suggest to not go much further with import resolution (unless > > > you already want to define modules). Perhaps we could have namespace > > > doing nothing else than namespacing... > >=20 > > If by "modules" you are referring to the file level, and not to > > something like packages or libraries, then that is exactly what I want > > to define! Influenced by Clojure, I recommended calling it a > > "namespace". However, I believe that naming it =E2=80=98mod' or =E2=80= =98module' is more > > suitable for its purpose. > >=20 > > mod olang.core.math > >=20 > > fn add(a: u32, b: u32) { > > return a + b > > } > > Not sure if I understand what you meant here. Maybe would be better > clarify what you understands as module. This concept is still blurry to = me. module =3D namespaced files. All symbols inside a file will share the same namespace implying the symbols of the object file will start with the name you gave to the module. I gave some examples bellow. > > > > These advantages come with the minor stipulation of initiating all = files with a > > > > namespace statement, which, in my view, is a small price to pay for= the > > > > benefits gained. > > > > > > I'm not keen on the idea of enforcing strict adherence to the folder > > > structure. > > > > > > How about we introduce a namespace block instead? Within this > > > block, everything would automatically have the namespace added as a > > > prefix. This could offer more flexibility while still maintaining > > > organization. > >=20 > > Don't you think that in practice almost every single file will > > namespace? C++ follows this pattern, and look at this Qt mirror [1], 6k > > files, all namespaced, they even created a macro to facilitate the > > work. > >=20 > > [1] https://github.com/search?q=3Drepo%3Aradekp%2Fqt+%2FQT_BEGIN_NAMESP= ACE%5Cn%2F&type=3Dcode&p=3D1 > > I prefer being explicit in this case (even if we need to write it for > every file). If you land on a random file, you can say for what the > binary the code will translate to without checking the folder structure. > (Dir tree organization is completely up to the developers).=20 The approach I suggested allows you to explicitly declare the module in each file. This way, anyone who opens a file can immediately understand what the code will translate to, without having to check the folder structure. 1. mod olang.core.math # <--- THIS LINE IS PART OF THE FILE 2.=20 3. fn add(a: u32, b: u32) { 4. return a + b 5. } I never suggested we should automatically create namespaces based on the file structure. Actually I described this approach in the Alternative section "1. Automatically create namespaces based on the filename" which I may not make it clear enough, but I dislike a lot. > If you land on a random file, you can say for what the > binary the code will translate to without checking the folder structure In the code organization example I provided, the first line of each file explicitly declares the module. Just check the first line and done! Just like java/golang package. > (Dir tree organization is completely up to the developers).=20 And they are! Let's say you have this code organization: - shared/ - arena.ol {mod arena} - list.ol {mod list} - hashmap.ol {mod hashmap} - fe/ - ast {mod fe.ast} - parser {mod fe.parser} - main.ol {mod main} Note that everything inside {} is the first line of the file. To compile this program we could use the follow command line: olang -I shared/ -o main main.ol Considering the *main.ol* start with following lines: mod main import arena import list import hashmap import fe.ast import fe.parser The olang compiler can automatically find the files inside the *fe* directory, because they match the file structure. But *arena*, *list*, and *hashmap* do not follow the file structure, so you should specify the directory where you can find them. The only convention is that dots in the module name mean slashes in the path location. This is required to avoid the ambiguity of having slashes meaning both division and module names. Although, In my opinion, if a developer creates a file named *veggies/zucchini.ol* and attempts to declare the module as *mod veg.zuc*, it would lead to confusion and errors. This is because the module name does not align with the file structure. A practical solution in this scenario would be to rename the file to *veg_zuc.ol* and declare the module as *mod veg_zuc*. This way, the module name matches the filename, making it easier to understand and manage. When compiling, you would specify the directory of *veg_zuc.ol* in the olang command. The generated symbols would remain largely the same (once *veg.zuc* translates to *veg_zuc*), maintaining the integrity of the structure. In practice is up to you how you use modules. You can create modules matching your entire project structure and the compiler will make the work without any extra argument, or you can create any structure you want and declare the include dir. > > > I think module has a different meaning. If you want to have modules, > > > for sure we have to discuss import resolution. IMHO namespace should= n't > > > do anything else than namespacing. > >=20 > > I believe you're right. It's almost impossible to discuss modules > > without bringing up imports. To me, the way C handles this is one of th= e > > most painful things in my life (hehe). > >=20 > > The main issue is that I never know where something is coming from, > > which is especially painful when I'm trying to replicate something I've > > already done. This also, often leads to unused includes over time > > because it's hard to determine if an include is actually being used. > > Could you please enlighten me the unused definitions problem? Does it > have any implications with performance? > > If this is so bad, why we cannot make the compiler smart enough to > detect them? I don't know what is the implication in terms of performance. I guess the object file may be larger if the header file has more than prototypes. But if you find unused includes no big deal in code maintenance, I have nothing else to say. > > If we abandon modules and just go with C++-like namespaces, I believe w= e > > we may want to endure C's painful include system. This is because the > > language won't have control over function names. The way the include > > system is designed sends a message to developers that including a file > > is akin to concatenating all the definitions into a single file. But > > yet I think it would be ok to have names imports even if we don't > > control the language names but it would be just a semantic tool. > >=20 > > Named Imports > > ------------- > >=20 > > mod myprog > >=20 > > import olang.core.math > >=20 > > fn main(): u32 { > > return olang.core.math::sum(1, 2) > > } > >=20 > > And even associate identifiers to it. > >=20 > > mod myprog > >=20 > > import olang.core.math as ocm > >=20 > > fn main(): u32 { > > return ocm::sum(1, 2) > > } > >=20 > > Note that there is no actually difference in between mangling and my > > module purpose, except the fact modules generates deterministic and > > friendly names that can be easily used in C and also easy to gen code, > > once to generate the assembly symbol of *olang.core.math::sum* we can > > just replace dots by underscores and double column to double > > underscores. > >=20 > > External Linkage > > ---------------- > >=20 > > We probably don't wanna to make all function global for external > > linkage. > > Could you please clarify what you mean with external linkage? When you write an implementation file (.cpp, .cxx, etc) your compiler generates a translation unit. This is the source file from your implementation plus all the headers you #included in it. Internal linkage refers to everything only in scope of a translation unit. External linkage refers to things that exist beyond a particular translation unit. In other words, accessible through the whole program, which is the combination of all translation units (or object files). https://stackoverflow.com/questions/1358400/what-is-external-linkage-and-= internal-linkage But looking at you answer above, it seems you understood the concept. > > So we may need a visibility keyword. > > The C already has this functionality, the *static* keyword... > Everything else is "public" by default. Do you see a problem on > following the same pattern? I prefer everything to be private by default to prevent leaking of implementation details which leads in less symbols in the object file. > > And to me, everything that can be imported should also be available > > for external linkage, even if we decide to do not generate an object > > file per module. I would recommend the usage of *export* or *pub*. I > > like *export* better. > > Why this has to be so complex? Seems like we would have to implement a > very complex system for compile a program with multiple files. I would > love to have something very simple where you compile down to a `.o` file > and the linking is done simple as GAS or GCC does. I said and I quote:=20 > > ... even if we decide to do not generate an object > > file per module "EVEN IF". I'm not suggesting us to do anything other than create a *.o* file. I'm not suggesting anything complex I don't know what makes you understand that. Basically what I said is: Let's do not make anything public by default. I just mentioned mentioned that we may don't wanna to generate an object file per module because olang has no header file. Meaning that we we always need to examine all files of the project anyway. But it just created more noise at the discussion, so you can ignore it. > > > Note that this is required no meter how we decide to handle imports. > >=20 > > No mangling > > ----------- > >=20 > > But what if I really need something to have the exact name? Lets say yo= u > > wanna integrate with a bootloader that is integrated on the link proces= s and > > expects a symbol called *kmain* to jump into? > >=20 > > Ok, I admit, in that case namespaces it is gonna be a pain in the ass. = But > > the good news is that these are exceptional, you don't need this for > > your entire application but only for a few functions. > >=20 > > I was wondering that we could have a *global* keyword where everything > > that is global assumes its own name and is always have public visibilit= y. > > You are assuming that all files has a mandatory namespace. I still > prefer the namespace being optional. The default behavior would be > every symbol wont have prefix. (1 to 1) with ELF binary symbols. > > IMHO this is what makes the language simple as C. Adding extra > functionality to protect the programming doing stuff and enabling > functionality with a lot of gymnastics feels like an unpleasant > experience. You gonna need to make a lot of gymnastic. Actually we do a lot of gymnastic every single time we prefix a C function to avoid conflicts. And many projects create macros to do the same job. I'm purposing that the language should provide the appropriated tooling for it. But I agree that we could make modules optional and you could provide the include directory in this case. > > Summarizing > > ----------- > >=20 > > We have a few options in the table. > >=20 > > 1. Use the names the way they are. (C approach) > >=20 > > Pros: > > - Simple, no magic, it is what it is. > > - Easy to produce debug info since the assembly symbol will be the > > function name. > > - No build gymnastics as well. The *make* program would solve our > problems for free (Even with partial compilation). No gymnastics in the modules suggestion. You can use make. You can make partial compilation. Never purpose the oppose. > >=20 > > Cons: > > - More challenge to keep the code out of name conflicts in large > > codebases. > > - Requires developers to manually namespace functions. > >=20 > > 2. Use mangled names (C++, Rust approach) > > The mangled names are basically to enable function overload. I think we > don't want this functionality on the language. I think we can ignore > this one. It is used to "enable function overload" but it isn't the only thing it solves. By mangled names I mean any strategy that generates names to avoid conflicts. It could even be a random string. Name mangling The names used in object file symbol tables and in linking are often not the same names used in the source programs from which the object files were compiled. There are three reasons for this: avoiding name collisions, name overloading, and type checking. The process of turning the source program names into the object file names is called name mangling. This section discusses mangling typically done to names in C, Fortran, and C++ programs. https://archive.ph/20130126113557/http://www.iecc.com/linker/linker05.htm= l#selection-481.0-487.90 > > > 3. Use modules (Zig approach (I think)) > >=20 > > Pros: > > - Keep the code out of naming conflicts > > - Deterministic assembly symbols permit integrate with C without any > > magic, you just need to follow the convention ns__fn. > >=20 > > Cons: > > - If you really need to have a specific name for your function you gonn= a > > need a no-mangle approach. > > Why? I mean you can still have the namespace and the freedom to use > namespace where you want. Are you assuming the namespace is mandatory > here? As I answered early in this thread a module is a namespaced file. If you need a function called *zucchini* and this function lies inside a file *veggies*/mod *veggies*, the *zucchini* file inside the object file will be called *veggies__zucchini*.