June 13, 2020
On 6/13/20 12:08 AM, Manu wrote:
> On Sat, Jun 13, 2020 at 2:05 PM Walter Bright via Digitalmars-d <digitalmars-d@puremagic.com <mailto:digitalmars-d@puremagic.com>> wrote:
> 
>     On 6/12/2020 8:25 PM, Andrei Alexandrescu wrote:
>      > On 6/12/20 8:54 PM, Walter Bright wrote:
>      >> On 6/12/2020 5:17 PM, Andrei Alexandrescu wrote:
>      >>> Not sure about that part - if linkage was static by means of
>     using the
>      >>> "static" keyword, multiple definitions may not be merged. (I
>     may be wrong,
>      >>> please correct me.) Consider:
>      >>>
>      >>> static inline int fun() {
>      >>>      static int x;
>      >>>      return ++x;
>      >>> }
>      >>>
>      >>> In C++, each translation unit containing a definition of fun()
>     will have a
>      >>> distinct address for x. I don't see how the bodies of those
>     functions can be
>      >>> merged.
>      >>
>      >> They are not merged in D, for the simple reason that
>     ModuleA.fun() and
>      >> ModuleB.fun() will have different (mangled) names presented to
>     the linker.
>      >
>      > For D the question is if they are merged if the function is
>     defined in a .di
>      > file and imported in two other modules.
> 
>     If the di file is mentioned on the command line to the compiler
> 
> 
> It's not, that's literally the point of a .di file.
> 
>     , yes (1)
>     instance of it appears in the executable. Otherwise, (0) instances
>     of it appear
>     in the executable. There are never 2 or more instances in the
>     executable.
> 
> 
> Exactly. And this is not a useful design.

All I can say is if that and/or other wrinkles prevent header-only libraries definition and use, yes, not a useful design.

So Manu, is the top-level goal "I want header-only libraries in D"?
June 13, 2020
On 6/13/20 7:31 AM, Johannes Pfau wrote:
> Am Sat, 13 Jun 2020 01:33:34 -0700 schrieb Walter Bright:
> 
>> On 6/12/2020 9:08 PM, Manu wrote:
>>>      If the di file is mentioned on the command line to the compiler
>>>
>>> It's not, that's literally the point of a .di file.
>>
>> No, it isn't. A .di file is more of a convention than a feature. It's a
>> module and does not get special treatment by the compiler.
>>
>>>      , yes (1)
>>>      instance of it appears in the executable. Otherwise, (0) instances
>>>      of it appear in the executable. There are never 2 or more instances
>>>      in the executable.
>>>
>>> Exactly. And this is not a useful design.
>>
>> I hate to say it, but these sorts of replies are completely useless to
>> resolving your issues. You omitted the *why*.
>>
>> Why can't you put it on the command line?
>>
> 
> 
> a.di:
> void foo() {}
> 
> b.d:
> import a;
> 
> c.d:
> import a;
> void main() {foo();}
> 
> 
> dmd -c b.d
> dmd -c c.d
> dmd b.o c.o => undefined reference to `_D1a3fooFZv'
> 
> dmd -c a.di b.d -ofb.o
> dmd -c a.di c.d -ofc.o
> dmd b.o c.o => undefined reference to `_D1a3fooFZv'
> 
> mv a.di a.d
> dmd -c a.d b.d -ofb.o
> dmd -c a.d c.d -ofc.o
> dmd b.o c.o => multiple definition of `_D1a12__ModuleInfoZ'
> 
> dmd -c a.d b.d -ofb.o -betterC
> dmd -c a.d c.d -ofc.o -betterC
> dmd b.o c.o => OK
> 
> BTW: If you do dmd -c a.di you get no object file output. So .di files
> are treated differently
> 
> 
> I think it's interesting that DMD seems to emit some (all?) normal
> functions as weak. Not sure if LDC and GDC do the same thing. Would also
> be interesting to see how all this interacts with staic & shared
> libraries, though I'm optimistic that it just works.
> 
> 
> 
> 
> So basically all that's missing for Manu's inline case would be to emit
> pragma(inlne) functions from non-root modules. Probably a 1-line change.

Should that go in bugzilla?


June 13, 2020
On 6/13/2020 4:31 AM, Johannes Pfau wrote:
> BTW: If you do dmd -c a.di you get no object file output. So .di files
> are treated differently

Yeah, you're right. Only in one spot, however, the .obj file is omitted. You can always rename it to .d


> I think it's interesting that DMD seems to emit some (all?) normal
> functions as weak.

It emits them all as COMDATs. This is so multiple definitions can be combined.

> So basically all that's missing for Manu's inline case would be to emit
> pragma(inlne) functions from non-root modules. Probably a 1-line change.

It's simply unnecessary for what Manu wants to achieve (header only libraries).

June 14, 2020
On Sun, Jun 14, 2020 at 4:20 AM Andrei Alexandrescu via Digitalmars-d < digitalmars-d@puremagic.com> wrote:

> On 6/13/20 12:08 AM, Manu wrote:
> > On Sat, Jun 13, 2020 at 2:05 PM Walter Bright via Digitalmars-d <digitalmars-d@puremagic.com <mailto:digitalmars-d@puremagic.com>>
> wrote:
> >
> >     On 6/12/2020 8:25 PM, Andrei Alexandrescu wrote:
> >      > On 6/12/20 8:54 PM, Walter Bright wrote:
> >      >> On 6/12/2020 5:17 PM, Andrei Alexandrescu wrote:
> >      >>> Not sure about that part - if linkage was static by means of
> >     using the
> >      >>> "static" keyword, multiple definitions may not be merged. (I
> >     may be wrong,
> >      >>> please correct me.) Consider:
> >      >>>
> >      >>> static inline int fun() {
> >      >>>      static int x;
> >      >>>      return ++x;
> >      >>> }
> >      >>>
> >      >>> In C++, each translation unit containing a definition of fun()
> >     will have a
> >      >>> distinct address for x. I don't see how the bodies of those
> >     functions can be
> >      >>> merged.
> >      >>
> >      >> They are not merged in D, for the simple reason that
> >     ModuleA.fun() and
> >      >> ModuleB.fun() will have different (mangled) names presented to
> >     the linker.
> >      >
> >      > For D the question is if they are merged if the function is
> >     defined in a .di
> >      > file and imported in two other modules.
> >
> >     If the di file is mentioned on the command line to the compiler
> >
> >
> > It's not, that's literally the point of a .di file.
> >
> >     , yes (1)
> >     instance of it appears in the executable. Otherwise, (0) instances
> >     of it appear
> >     in the executable. There are never 2 or more instances in the
> >     executable.
> >
> >
> > Exactly. And this is not a useful design.
>
> All I can say is if that and/or other wrinkles prevent header-only libraries definition and use, yes, not a useful design.
>
> So Manu, is the top-level goal "I want header-only libraries in D"?
>

It is one among multiple use cases in that category. It's essentially the
one I describe by use-case #1.
That is one useful case. It's not limited to that though, it comes up in
various situations.

For instance, I do a lot with DLL's... it's typical to load a DLL, and then bind to a single function that creates an instance of some object that the DLL provides. From there, further calls into the library are via the object vtable.
>From this point, there are a few design pressures that lead to inline
functions:
1. v-calls are slow, and trivial operations (ie, getters/setters) should
just be inlines where it makes sense. Cross-module calls are not desirable.
2. DLL's ABI is essentially part of the API, and changes to the ABI are
breaking changes to the lib.
  - Skilled design is to have fewer virtual functions that 'do stuff', with
flexibility in how it's called and lots of soft-extensibility option
arguments.
    * Enhancement to a lib can be made by adding a new item to an enum,
rather than breaking the ABI.
  - This broad style of function is inconvenient for users, and typical use
cases often wrap these work functions up in convenience inline calls, to
automate a complex calling scheme.
3. Such libraries are installed by the package manager in some location,
along with their 'headers', which root path is automatically added in a
build script somewhere.
  - It is not the job of the application's build environment to determine
what functions it calls from a lib and then cherry-pick source files from
the lib and include them into the applications build... that creates
compile-time couplings which are awkward at best, and naturally break-down
over time. It self-defeats the use of DLL's.

A build system might not even know how to identify the paths to a particular library's random source files, and it shouldn't be the client's responsibility to understand a lib's source tree. It's hard to know what source files you need to include and build... I probably don't call every function in the lib; I don't want to include the source for a DLL into my application; that's self-defeating.

TL;DR, right now, I care about DLL's, and inline functions are an essential part of DLL-based libraries.

It doesn't end there though either; there are so many cases where a reference to a lib should not create a 'hard' coupling between projects. I have often had situations involving 'optional' functionality; if a call is never made, then the dependency beneath that call isn't inferred on the client. An inline with no references naturally doesn't pull the dependency reference into the binary unless it's actually called. You could argue for stripping to solve that case, but that's a much more brittle and unsatisfying solution.


June 14, 2020
On Sun, Jun 14, 2020 at 5:55 AM Walter Bright via Digitalmars-d < digitalmars-d@puremagic.com> wrote:

> On 6/13/2020 4:31 AM, Johannes Pfau wrote:
> > BTW: If you do dmd -c a.di you get no object file output. So .di files are treated differently
>
> Yeah, you're right. Only in one spot, however, the .obj file is omitted.
> You can
> always rename it to .d
>

By definition; we're talking about libraries here. Inline's are only
relevant when calling into foreign code.
I don't molest the source tree of my libraries. There's a high probability
the directory doesn't even have write permissions.


June 21, 2020
On Saturday, 13 June 2020 at 18:24:18 UTC, Andrei Alexandrescu wrote:
> On 6/13/20 7:31 AM, Johannes Pfau wrote:
>> 
>> So basically all that's missing for Manu's inline case would be to emit
>> pragma(inlne) functions from non-root modules. Probably a 1-line change.
>
> Should that go in bugzilla?

I don't see why there should not be a bugzilla for it.

@Manu, pardon my skipping the 11 pages of replies between the first and last posts, so if it's already been said, please ignore.

I think trying to impose the C/C++ notion of inline as a linkage modifier into D is at odds with modules.  I'm going to make a potentially disagreeable statement and say that there is no external or internal linkage in D.  Rather there's language linkage, e.g: `extern(C++)`; and then there's module linkage, where a given declaration resolves to the same symbol across all TUs that import its residing module, but otherwise not strictly visible outside that.

To address your laments, it may be wise to pay attention to the direction that `inline` is heading in C++ modules.

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1498r1.html#inline
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1779r3.html

Notably the sentence: "Within interface units of modules, we suggest converging on an interperation more firmly rooted in the semantics: an inline entity (function definition or variable initialization) is semantically incorporated into (or inlined into) the interface of a module."

Which I interpret as, given:

    module mod;
    pragma(inline, true) void fun() { ... }

Any module that imports `mod` (called non-root),  will have the `fun` emitted into the module as well.  This would be implemented using the support of weak (ELF) or selectany (COFF), so the linker will throw away all duplicated definitions.

However, to satisfy your "emit to the binary only when it is called" constraint, it will also have to be discard-able at compile-time.  But I'm not sure whether that really a desirable feature to have.  At the very least, it should only extend to non-root modules, so there's always one copy in the root module it was declared, to avoid linker errors.
3 4 5 6 7 8 9 10 11 12 13
Next ›   Last »