• Re: module_param

    From Dmitry A. Kazakov@21:1/5 to James Harris on Tue Nov 23 16:13:26 2021
    On 2021-11-23 15:36, James Harris wrote:
    I'm not too sure what's going on here but you guys might find the
    following to be of interest. It seems to be a way to provide a default
    value for instantiation of a module - so that a piece of code can be
    loaded into memory with a parameter set at load time rather than when a function is invoked.

    ... and the next instance overriding the first. Such a fun!

    Shared generic bodies is a lot of joy to implement. GCC just blows up
    the code copying each instance of a generic/template a whole.

    But the real ecstasy begins with instances within instances, parameters
    passed from one instance to another and then you have to determine if a
    thing within two instances visible along two different paths is same
    thing or not.

    GNAT Ada is fighting this mess for about thirty years and still is buggy
    as hell there.

    --
    Regards,
    Dmitry A. Kazakov
    http://www.dmitry-kazakov.de

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Harris@21:1/5 to All on Tue Nov 23 14:36:21 2021
    I'm not too sure what's going on here but you guys might find the
    following to be of interest. It seems to be a way to provide a default
    value for instantiation of a module - so that a piece of code can be
    loaded into memory with a parameter set at load time rather than when a function is invoked.

    The code is short:

    int count = 1;
    module_param(count, int, 0);

    and it's from about 22 minutes into

    https://youtu.be/1cPpU966aJ0

    Two points:

    1. I am surprised that's eveb possible in C. Can anyone more familiar
    with C make sense of what might be going on under the covers?

    2. More importantly, is it a helpful approach which could be used in
    other languages?

    I've previously suggested that constants defined at file level are
    effectively read-only parameters to any functions within the file, and
    that seems to be what the code is doing. But it also, apparently, allows setting of a default and for that default to be overridden.

    Would it be good for constants (rather than global variables) with any particular constants being set either by a user or by another program
    when a module is loaded?

    Thoughts?


    --
    James Harris

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Harris@21:1/5 to Dmitry A. Kazakov on Tue Nov 23 20:21:07 2021
    On 23/11/2021 15:13, Dmitry A. Kazakov wrote:
    On 2021-11-23 15:36, James Harris wrote:

    I'm not too sure what's going on here but you guys might find the
    following to be of interest. It seems to be a way to provide a default
    value for instantiation of a module - so that a piece of code can be
    loaded into memory with a parameter set at load time rather than when
    a function is invoked.

    ... and the next instance overriding the first. Such a fun!

    :-)

    Wouldn't each instance be separate? I can't see how one instance could
    override another.

    AISI there are two forms of genericity: implicit and explicit. The
    implicit is what one might call polymorphic. A function would
    automatically process the types of its arguments as in

    int i
    real r
    f(i)
    f(r)

    By contrast, the explicit approach would programmatically instantiate
    different modules more akin to the creation of fi and fr in

    int i
    real r
    fi = f<int>
    fr = f<real>
    fi(i)
    fr(r)

    Perhaps the latter is closer to the idea of instantiating a module.


    Shared generic bodies is a lot of joy to implement. GCC just blows up
    the code copying each instance of a generic/template a whole.

    But the real ecstasy begins with instances within instances, parameters passed from one instance to another and then you have to determine if a
    thing within two instances visible along two different paths is same
    thing or not.

    "Two paths" suggests diamond pattern and an inheritance tree. I don't
    think any kind of inheritance is required for the kind of genericity
    needed in the above.

    One thing I think you are saying and I would agree with you on in spades
    is that there are many 'solutions' to these problems but no one clearly
    best approach.


    --
    James Harris

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Dmitry A. Kazakov@21:1/5 to James Harris on Tue Nov 23 23:06:31 2021
    On 2021-11-23 21:21, James Harris wrote:
    On 23/11/2021 15:13, Dmitry A. Kazakov wrote:
    On 2021-11-23 15:36, James Harris wrote:

    I'm not too sure what's going on here but you guys might find the
    following to be of interest. It seems to be a way to provide a
    default value for instantiation of a module - so that a piece of code
    can be loaded into memory with a parameter set at load time rather
    than when a function is invoked.

    ... and the next instance overriding the first. Such a fun!

    :-)

    Wouldn't each instance be separate? I can't see how one instance could override another.

    If you share the code it must. Compare it to recursive calls. Recursive
    calls share the code. Inlining recursive calls is not always possible,
    which is a hint why generic instantiation per copy-paste-substitute is
    not a bright idea.

    AISI there are two forms of genericity: implicit and explicit.

    This is an independent issue. Regardless whether you must repeat all
    actual parameters all times or do it once, you have the problem.
    Repeating parameters only adds up to the havoc because you must
    reinterpret the actual parameter each time and the result may and will
    depend on the context.

    "Two paths" suggests diamond pattern and an inheritance tree. I don't
    think any kind of inheritance is required for the kind of genericity
    needed in the above.

    It is not inheritance. Diamond pattern equally applies to both
    inheritance and generic instantiations and namespaces.

    One thing I think you are saying and I would agree with you on in spades
    is that there are many 'solutions' to these problems but no one clearly
    best approach.

    The best approach is not to go this path. Ada and C++ both tried and
    failed. Generics/templates always end in a mess.

    --
    Regards,
    Dmitry A. Kazakov
    http://www.dmitry-kazakov.de

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Harris@21:1/5 to Dmitry A. Kazakov on Wed Nov 24 10:19:14 2021
    On 23/11/2021 22:06, Dmitry A. Kazakov wrote:
    On 2021-11-23 21:21, James Harris wrote:
    On 23/11/2021 15:13, Dmitry A. Kazakov wrote:
    On 2021-11-23 15:36, James Harris wrote:

    I'm not too sure what's going on here but you guys might find the
    following to be of interest. It seems to be a way to provide a
    default value for instantiation of a module - so that a piece of
    code can be loaded into memory with a parameter set at load time
    rather than when a function is invoked.

    ... and the next instance overriding the first. Such a fun!

    :-)

    Wouldn't each instance be separate? I can't see how one instance could
    override another.

    If you share the code it must.

    I wouldn't share the code! AISI the point of multiple instantiation is
    that each instance would be different.

    (As it happens, if the only thing which was different was the constants
    and they were to be separated out from the code then it may be possible
    to have one copy of the code but multiple rodata sections. But that's an implementation detail. In simple terms the point of different
    instantiations would be that the loaded code would be different.)


    --
    James Harris

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Dmitry A. Kazakov@21:1/5 to James Harris on Wed Nov 24 12:34:36 2021
    On 2021-11-24 11:19, James Harris wrote:
    On 23/11/2021 22:06, Dmitry A. Kazakov wrote:
    On 2021-11-23 21:21, James Harris wrote:
    On 23/11/2021 15:13, Dmitry A. Kazakov wrote:
    On 2021-11-23 15:36, James Harris wrote:

    I'm not too sure what's going on here but you guys might find the
    following to be of interest. It seems to be a way to provide a
    default value for instantiation of a module - so that a piece of
    code can be loaded into memory with a parameter set at load time
    rather than when a function is invoked.

    ... and the next instance overriding the first. Such a fun!

    :-)

    Wouldn't each instance be separate? I can't see how one instance
    could override another.

    If you share the code it must.

    I wouldn't share the code! AISI the point of multiple instantiation is
    that each instance would be different.

    That by no means imply different code: sin(1.0) /= sin(0.5), same code
    still.

    You are confusing a lot of different things:

    1. Equivalence. Named vs. structural. When two instances are considered logically same.

    2. Shared bodies vs. macro expansions and all infinite points inbetween.

    (As it happens, if the only thing which was different was the constants
    and they were to be separated out from the code then it may be possible
    to have one copy of the code but multiple rodata sections. But that's an implementation detail. In simple terms the point of different
    instantiations would be that the loaded code would be different.)

    It is a detail that changes a lot. Especially when generics become more elaborated. At some point you will allow functions as parameters. Then
    oops, what about your beloved "bound" functions? You need types as
    parameters. Then what about instances of other generics as parameters?
    Then what about a whole generic as a parameter? The formal generic gets instantiated inside the instance with whatever parameters local or
    externals. Generics is an abyss with no bottom...

    --
    Regards,
    Dmitry A. Kazakov
    http://www.dmitry-kazakov.de

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Harris@21:1/5 to Dmitry A. Kazakov on Fri Nov 26 17:32:04 2021
    On 24/11/2021 11:34, Dmitry A. Kazakov wrote:
    On 2021-11-24 11:19, James Harris wrote:
    On 23/11/2021 22:06, Dmitry A. Kazakov wrote:
    On 2021-11-23 21:21, James Harris wrote:
    On 23/11/2021 15:13, Dmitry A. Kazakov wrote:
    On 2021-11-23 15:36, James Harris wrote:

    I'm not too sure what's going on here but you guys might find the
    following to be of interest. It seems to be a way to provide a
    default value for instantiation of a module - so that a piece of
    code can be loaded into memory with a parameter set at load time
    rather than when a function is invoked.

    ... and the next instance overriding the first. Such a fun!

    :-)

    Wouldn't each instance be separate? I can't see how one instance
    could override another.

    If you share the code it must.

    I wouldn't share the code! AISI the point of multiple instantiation is
    that each instance would be different.

    That by no means imply different code: sin(1.0) /= sin(0.5), same code
    still.

    You are confusing a lot of different things:

    1. Equivalence. Named vs. structural. When two instances are considered logically same.

    2. Shared bodies vs. macro expansions and all infinite points inbetween.

    I am not sure what you are thinking of but AFAICS none of that is
    relevant. Rather, the kind of instantiation being implemented by the aforementioned approach would customise modules as they are loaded into
    memory.

    The initial case just loaded a custom constant but I could see it being
    used to make customisations which were more general.

    Some examples to illustrate how it might be used:

    module_param(int, MAX_NICS, 8)
    module_param(int, MAX_OPEN_FILES, 56)
    module_param(float, PI, 3.141)
    module_param(int, BITWIDTH, 64)

    Multiple executable images could be created from one load module. Each
    image would have the parameters set before it started.


    --
    James Harris

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Dmitry A. Kazakov@21:1/5 to James Harris on Fri Nov 26 21:22:48 2021
    On 2021-11-26 18:32, James Harris wrote:
    On 24/11/2021 11:34, Dmitry A. Kazakov wrote:

    You are confusing a lot of different things:

    1. Equivalence. Named vs. structural. When two instances are
    considered logically same.

    2. Shared bodies vs. macro expansions and all infinite points inbetween.

    I am not sure what you are thinking of but AFAICS none of that is
    relevant. Rather, the kind of instantiation being implemented by the aforementioned approach would customise modules as they are loaded into memory.

    The implementation is irrelevant if semantics is undefined. I assure
    you, there exist effective methods of sharing code producing whatever semantics.

    The initial case just loaded a custom constant but I could see it being
    used to make customisations which were more general.

    Some examples to illustrate how it might be used:

      module_param(int, MAX_NICS, 8)
      module_param(int, MAX_OPEN_FILES, 56)
      module_param(float, PI, 3.141)
      module_param(int, BITWIDTH, 64)

    Since this is untyped it makes no sense at all.

    Otherwise, to the point #1 consider whether instances

    Foo (A, B, C)

    and

    Foo (E, F, G)

    are same.

    Multiple executable images could be created from one load module. Each
    image would have the parameters set before it started.

    Here is an example of diamond with generics:

    generic
    type T is range <>;
    package Generic_First is
    subtype S is T; -- Renaming the actual
    end Generic_First;

    generic
    with package P is new Generic_First (<>);
    package Generic_Second is
    package PP renames P;
    end Generic_Second;

    generic
    with package Q is new Generic_Second (<>);
    with package R is new Generic_Second (<>);
    package Generic_Third;

    Instances:

    package A is new Generic_First (Integer);
    package B is new Generic_Second (A);
    package C is new Generic_Second (A);
    package D is new Generic_Third (B, C);

    Now since equivalence is nominal inside Generic_Third:

    package Generic_Third is
    X : Q.PP.S; -- Integer
    Y : R.PP.S; -- Integer
    begin
    X := Y; -- Illegal, nominally different,
    -- even if from same instance
    end Generic_Third;

    --
    Regards,
    Dmitry A. Kazakov
    http://www.dmitry-kazakov.de

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Harris@21:1/5 to Dmitry A. Kazakov on Fri Nov 26 22:06:56 2021
    On 26/11/2021 20:22, Dmitry A. Kazakov wrote:
    On 2021-11-26 18:32, James Harris wrote:

    ...

    Some examples to illustrate how it might be used:

       module_param(int, MAX_NICS, 8)
       module_param(int, MAX_OPEN_FILES, 56)
       module_param(float, PI, 3.141)
       module_param(int, BITWIDTH, 64)

    Since this is untyped it makes no sense at all.

    The first argument - int or float - was meant to be the type.

    I should add that the above is not the Linux syntax but is meant purely
    for illustration. I guess it would make sense for such module parameters
    to be defined before a module was loaded but also for a module to be
    able to have defaults for any parameters.


    --
    James Harris

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Dmitry A. Kazakov@21:1/5 to James Harris on Fri Nov 26 23:23:54 2021
    On 2021-11-26 23:06, James Harris wrote:
    On 26/11/2021 20:22, Dmitry A. Kazakov wrote:
    On 2021-11-26 18:32, James Harris wrote:

    ...

    Some examples to illustrate how it might be used:

       module_param(int, MAX_NICS, 8)
       module_param(int, MAX_OPEN_FILES, 56)
       module_param(float, PI, 3.141)
       module_param(int, BITWIDTH, 64)

    Since this is untyped it makes no sense at all.

    The first argument - int or float - was meant to be the type.

    The generics above are untyped. E.g. the third parameter accepts int and
    float. This sort of stuff is plain macros. Use preprocessor be done with
    that.

    Ada generics are weakly typed and that is a huge problem. But they are
    far stronger than the above mess which would be impossible in Ada:

    generic
    type First is range <>;
    Second : First;
    Third : Float;
    package Module_Param is ...

    The formal First will not accept float. The formal Second will not
    accept Pi. The formal third will not accept 8.

    --
    Regards,
    Dmitry A. Kazakov
    http://www.dmitry-kazakov.de

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)