c3c icon indicating copy to clipboard operation
c3c copied to clipboard

Support ad hoc function and type submodule declarations

Open lerno opened this issue 1 year ago • 11 comments

Possible syntax

module std::foo;
// Creates a sub module std::foo::bar in which hello() is placed.
fn void bar::hello() 
{
  ...
}

lerno avatar Oct 03 '24 20:10 lerno

Assuming this only allows a single level of depth? So you can do bar::hello() but maybe not bar::baz::hello()?

Caleb-o avatar Oct 04 '24 02:10 Caleb-o

Exactly, it will be limited to single level for readability and also implementation should be more straightforward.

lerno avatar Oct 04 '24 08:10 lerno

If we look at the OOP world, do they ever create an implicit class in this sort of manner?

Personally I think a module is a fundamental organisational unit, I wouldn't want to create one implicitly, possibly by accident. I would always want to know I made an organisational unit and that I can use that further to do other interesting things with it.

I would want to be able to search for it, with module bar::new_module; to be able to find it.

Having things created without knowing we create a "mistrust" of modules as they are not concrete things I can easily look up. I feel like this would be a big missed opportunity to get people on-board with modules as something they can use and trust.

joshring avatar Oct 08 '24 09:10 joshring

@joshring I feel like this is somewhat similar to declaring nested namespaces and classes. In something like C# and Java I believe, I could make a whole lot of nested classes and namespaces. I don't think this is too different from that, except this proposal only allows for a single level of depth.

Talking about OOP, I think something like Java allows you to just make anonymous classes and such, which might go against your searchability argument. So there's definitely worse options that other languages allow and this seems pretty reasonable from what I understand.

Caleb-o avatar Oct 08 '24 09:10 Caleb-o

This is still fairly explicit though:

public class Container
{
    class Nested
    {
        Nested() { }
    }
}

and you can search for class Nested

Talking about OOP, I think something like Java allows you to just make anonymous classes and such, which might go against your searchability argument. So there's definitely worse options that other languages allow and this seems pretty reasonable from what I understand.

joshring avatar Oct 08 '24 10:10 joshring

module std::foo;
// Creates a sub module std::foo::bar in which hello() is placed.
fn void bar::hello() 
{
  ...
}

When someone searches for bar they might find it here on this line, but they don't have any idea what it is, and there is no definition elsewhere you can look up.

In this example you always know it's a nested class (even me as a non-C# dev)

public class Container
{
    class Nested
    {
        Nested() { }
    }
}

joshring avatar Oct 08 '24 10:10 joshring

I think there is one point that makes foo::bar() more obvious to what it is and that's the foo::. As far as I'm aware, the only thing that uses :: are modules. So you declare modules using this and also qualify things this way. Since this is used at the declaration, I feel like that might be more obvious than if it were to use some other pattern. So if I saw a function declaration with fn void foo::bar() {...} then I would probably assume it has something to do with modules, then eventually understand it was placed within the foo module.

There's one thing I'm not sure we've talked about though, how does this play with method syntax? (Maybe I've missed this)

A:

fn void foo::MyStruct.bar() { ... }

B:

fn void MyStruct.foo::bar() { ... }

Or is this solely for free functions?

Caleb-o avatar Oct 08 '24 10:10 Caleb-o

So there is a hint that a module foo exists, but to my eyes there is no definition I would recognise for foo

Anonymous classes in Java, Polygon still exists outside as a definition I can look up

class Polygon {
   public void display() {
      System.out.println("Inside the Polygon class");
   }
}

class AnonymousDemo {
   public void createClass() {

      // creation of anonymous class extending class Polygon
      Polygon p1 = new Polygon() {
         public void display() {
            System.out.println("Inside an anonymous class.");
         }
      };
      p1.display();
   }
}

class Main {
   public static void main(String[] args) {
       AnonymousDemo an = new AnonymousDemo();
       an.createClass();
   }
}

joshring avatar Oct 08 '24 11:10 joshring

You can also do this with interfaces in Java. I think that was where I was thinking about it. You can just create anonymous classes using an interface, which you might not pick up from search unless you go looking. There's also class expressions in languages like JS, which might not be spotted, also caused by the nature of JS.

So really, my main line of thinking is that a lot of languages have weird concepts you probably won't know or understand until you come across them and do a lookup in the docs. I'm still learning concepts about languages I've used now. That's also not really a bad thing. But anyway, I don't think foo::bar() is too crazy of a concept in the grand scheme of things and :: makes it more obvious of what it could be doing and you also have to qualify the function as foo::bar() to use it.

Caleb-o avatar Oct 08 '24 12:10 Caleb-o

Just as a clarification:

This thing is valid today:

fn void std::core::String.new_thing(self)
{}

And is nothing special, just an unambiguous way to write:

fn void String.new_thing(self)
{}

Note that for various reasons it doesn't matter if this new_thing method is defined in an imported module or not. It has immediate availability in all modules.

In my thinking it doesn't make sense for things like struct my_sub::AStruct { ... }, but it would be mainly for the occasional constructor function and to make converted constant enums from C APIs more friendly.

lerno avatar Oct 08 '24 13:10 lerno

but it would be mainly for the occasional constructor function and to make converted constant enums from C APIs more friendly.

But anyway, I don't think foo::bar() is too crazy of a concept in the grand scheme of things and :: makes it more obvious of what it could be doing

I think open for extension is fine, but implicitly organising code seems like a mis-step because it can be over-used and become hard to maintain.

Not everything added is used in the way you expect is my concern.

I think one of the hallmarks of successful features in languages is easily being able to find the definitions of concepts in the code. That's why things like C/C++ macros are so hard, because they can nest and you don't know where the code is, leading to great complexity.

Perhaps not as bad as that, but could be easily misused, leading to spaghetti code from less experienced C3 programmers (which will be the majority for a while as C3 is new).

joshring avatar Oct 08 '24 15:10 joshring

Having investigated the complexity and the look of it, it looks like it's not worth it.

lerno avatar Dec 25 '24 19:12 lerno