j3-fortran / fortran_proposals

Proposals for the Fortran Standard Committee
178 stars 15 forks source link

Namespace for modules #1

Open certik opened 4 years ago

certik commented 4 years ago

So you can require module data to be referenced like module.var:

use, namespace :: utils
...
call utils%savetxt()

One issue with just use utils is that it still pollutes your local namespace with savetxt, so that's the reason for use, namespace :: utils.

Other alternatives for syntax: use utils, only (or perhaps use utils, only:). Another alternative is use namespace utils (suggested by Milan Curcic). Or perhaps use, namespace :: utils, to by compatible with the existing syntax like use, intrinsic :: iso_fortran_env.

Initially proposed by Michael Zingale and further discussed at Twitter.

gronki commented 4 years ago

My opinion is that it is a bad idea to use word "import" for a completely different meaning just because other languages do that. In Fortran as of now including modules is accomplished by "use", not "import", and i think it's important to stick to that to not introduce confusion.

Dominik

śr., 23 wrz 2020 o 02:44 Ondřej Čertík notifications@github.com napisał(a):

I like the word import the most. But as you said, it might be technically infeasible to use import for both. We need to see.

On Tue, Sep 22, 2020, at 6:09 PM, septcolor wrote:

(I am sorry if the following has already been discussed in other posts or thread...)

Another popular keyword used for this purpose is import (most notably Python), though this keyword is already used for different purposes (interface blocks) in Fortran. Because import is very common in other languages for importing modules, I guess another approach may be to "reuse" that keyword for importing a module name only (as a namespace), like import mylib at a top of a given scope (which I think corresponds to use, with :: mylib and use, namespace :: mylib).

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub < https://github.com/j3-fortran/fortran_proposals/issues/1#issuecomment-697046123>, or unsubscribe < https://github.com/notifications/unsubscribe-auth/AAAFAWDYE32IZ2CVYXTGUILSHE4EPANCNFSM4JBFRGNA .

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/j3-fortran/fortran_proposals/issues/1#issuecomment-697055704, or unsubscribe https://github.com/notifications/unsubscribe-auth/AC4NA3MES2W4RU7XMH4HOILSHFAGZANCNFSM4JBFRGNA .

klausler commented 4 years ago

import conflicts with existing usage; with doesn't make immediate sense to the new reader.

Consider something like use :: mylib, ns => * or use, as(ns) :: mylib.

(Edit: see below, I think use :: ns => mylib is better.)

certik commented 4 years ago

Here are the options proposed so far, by category:

Add a keyword after use in line with the existing syntax for intrinsic:

Extend the only keyword:

Extend the renaming => syntax:

Use two keywords:

Use a new keyword entirely:

certik commented 4 years ago

I think we need to implement this in a compiler and actually use it.

Looking at these alternatives, the following starts to look nice:

Easy to type, no ::, no ,, and this will be the most common use case. Maybe even like this:

klausler commented 4 years ago

I think we need to implement this in a compiler and actually use it.

Looking at these alternatives, the following starts to look nice:

  • use namespace mylib

Easy to type, no ::, no ,, and this will be the most common use case. Maybe even like this:

  • use module mylib

Doesn't work with fixed-form source, unfortunately. USENAMESPACEMYLIB is ambiguous, and unlike MODULEPROCEDUREFOO, not clear from the context.

certik commented 4 years ago

Doesn't work with fixed-form source, unfortunately. USENAMESPACEMYLIB is ambiguous, and unlike MODULEPROCEDUREFOO, not clear from the context.

I forgot about that. Another example for #108. One option would be to only introduce this syntax in free form, it would not be available in fixed form --- but that's a bigger decision to be made separately.

klausler commented 4 years ago

Doesn't work with fixed-form source, unfortunately. USENAMESPACEMYLIB is ambiguous, and unlike MODULEPROCEDUREFOO, not clear from the context.

I forgot about that. Another example for #108. One option would be to only introduce this syntax in free form, it would not be available in fixed form --- but that's a bigger decision to be made separately.

All Fortran semantics are orthogonal to the source form. And it's easy to accommodate fixed form here -- you listed many workable alternatives above.

wclodius2 commented 4 years ago

Before implementing it it needs to be specified well enough that you know what you are implementing. First in Fortran punctuation is very useful, particularly to remove ambiguities in fixed source form. Second you will want to accommodate the module-nature keywords: intrinsic and the rarely used nonintrinsic. You will also probably want to accommodate module renaming. I am inclined to a single new keyword as it can be unambiguous and reduces typing

milancurcic commented 4 years ago

Here's one more, inspired by @klausler but consistent with use ..., only::

use iso_fortran_env, as: env

If you want to use the namespace as is, then it needs some extra typing:

use iso_fortran_env, as: iso_fortran_env

Note that use iso_fortran_env, as: env is similar to Python's import numpy as np.

ivan-pi commented 4 years ago

Stavros (can't find his github name) left a comment in the monthly call, how would the namespace syntax work together with submodules?

everythingfunctional commented 4 years ago

Here's one more, inspired by @klausler but consistent with use ..., only::

use iso_fortran_env, as: env

Stylistically I prefer use iso_fortran_env, as: env over use, namespace :: env => iso_fortran_env, but the later is more consistent with existing syntax, and simplifies in a more consistent and concise way.

everythingfunctional commented 4 years ago

Stavros (can't find his github name) left a comment in the monthly call, how would the namespace syntax work together with submodules?

Would it be relevant? Currently, consumers of a module can't tell if it uses submodules, so there's no issue on that side. And anything in scope in a module is implicitly in scope in a submodule, so I don't think there's an issue on that side either.

milancurcic commented 4 years ago

Tagging @smeskos here.

certik commented 4 years ago

I like use iso_fortran_env, as: env, I think we all do.

The question is how to simplify:

use iso_fortran_env, as: iso_fortran_env

Some options:

septcolor commented 4 years ago

Just FWIW, Chapel uses an empty identifier list after only (https://chapel-lang.org/docs/primers/modules.html) to import only the module name, which may translate to

  use mymod, only:   !! nothing written here

(which is equal to import mymod; that allows only a qualified access of module entities).

Nim uses a similar approach by excluding all entities in the module via the keyword nil (e.g., from mymod import nil), which may correspond to

  use mymod, only: none

(but this approach needs an additional keyword like "none" etc...)

Julia uses both using and import, where using imports all the exported module entities by default, while import imports only the module name.

certik commented 4 years ago

@septcolor you are right. Here is a comparison table:

Python Julia Chapel Fortran
import A import A use A only use A, only:
import A as B import A as B use A as B only use B => A, only:
from A import x using A: x use A only x use A, only: x
from A import x as y import A: x as y use A only x as y use A, only: y => x
from A import * using A use A use A

Note 1: Julia's syntax for import A as B and import A: x as y is only implemented as a PR (https://github.com/JuliaLang/julia/pull/37396) from 3 weeks ago (!), but not merged yet.

Note 2: One can use import A: x instead of using A: x in Julia.

Note 3: Chapel's syntax use A as B only isn't mentioned in the docs, but it seems that would be the natural way (I haven't tested it).

Note 4: Chapel also has an import syntax, but it seems redundant (?) to the use syntax above.

Given this and the Chapel's precedent, I now prefer:

klausler commented 4 years ago

use A, only: ! empty to get a namespace is not at all clear, and it doesn't allow for the otherwise orthogonal creation of both a namespace as well as unqualified importation of some names.

milancurcic commented 4 years ago

I don't like use A, only: because to a naive reader, it's not clear what it means. To me (experienced reader), it's still awkward and seems like it's trying to fit an existing syntax that is used for something else.

Of @certik's alternative syntaxes, I like this one best:

use iso_fortran_env, as is
wclodius2 commented 4 years ago

FWIW having a keyword after only: is prone to namespace conflicts. For example, my stdlib_bitsets module defines a function none.

septcolor commented 4 years ago

@klausler As far as I experimented, it seems possible to import the module name as well as module entities by writing two statements, e.g. (in Chapel's case):

use Time only;
use Time only Timer as Foo;

proc test()
{
    var timer = new Time.Timer();
    writeln( timer.type:string );  // Timer

    var foo = new Foo();
    writeln( foo.type:string );  // Timer
}

test();

but I agree that use mymod, only: !! nothing here looks somewhat awkward (at least initially). If there were some keyword representing "nothing", we could use it here, but as @wclodius2 says, none etc can conflict with existing symbols.

Personally, I prefer using the keyword import most (which is very natural in its meaning), but it is "reserved" by the use in interface blocks. I think one could define "except this, except that" rules to enable overloading the meaning of import, but I'm afraid this would introduce additional complications (possibly both for compiler implementation and user experiences)...

klausler commented 4 years ago

For what it's worth, Haskell has import [qualified] ModuleName [as Alias] [[hiding] (names)].

Qualified names are available with and without qualified -- the module name or its alias always becomes available as what you all are calling a "namespace". When qualified doesn't appear, the imported names are also available without qualification.

The list of imported names can be absent, in which case all exported names from the module are imported. And it can be negated with hiding to import everything but some names.

Haskell also allows multiple modules to be imported into the same alias, so long as there are no conflicts. And module aliases can be exported, too, for use in other modules. This is useful -- it lets one compose a new module using names imported from others.

smeskos commented 4 years ago

@everythingfunctional:

Would it be relevant?

Perhaps not. I am trying to figure this out. Please see the two examples below. Do they make any sense or my confusion is irrelevant to the namespace proposal?

First example with submodules; We have the following module/submodule system: module Base submodule A, submodule B submodule A1, submodule A2

Declaration: submodule (Base)A, submodule(Base)B submodule(Base : A)A1,
submodule(Base : A)A2

program main
use, namespace :: Base
!will Base be able to see every submodule?
call Base%A%A1%mySubroutine(args, ...)
end program

Second example:

module All, module A, module B, module C, module D, etc...

module All
use, namespace :: A, B, C, D,...
end module All
! Is the following correct?
program main
use, namespace ::all
call all%A%mySubroutineA()
end program main
everythingfunctional commented 4 years ago

Submodules aren't supposed to be publicly knowable, so if mySubroutine is publicly available from Base, then it would be accessible as Base%mySubroutine and there would be no need for any reference to the submodule. If something is not declared in the module, it is not publicly accessible.

wclodius2 commented 4 years ago

As is common with arguments about syntax, we are "bike shedding". Everyone understands syntax, so everyone has a different opinion on it. I can come up with a large number of syntaxes. For example a standalone keyword:

namespace, intrinsic:: env=>iso_fortran_env
with, intrinsic::  env=>iso_fortran_env
using, intrinsic:: env=>iso_fortran_env
import, intrinsic:: env=>iso_fortran_env
employ, intrinsic:: env=>iso_fortran_env
source, intrinsic:: env=>iso_fortran_env
qualified, intrinsic:: env=>iso_fortran_env
as is, intrinsic:: env=>iso_fortran_env

many of the same keywords could be used as attributes in the early part of a use statement, but then the standard has to explain why there is no rename or only list;

use, namespace, intrinsic:: env=>iso_fortran_env
use, with, intrinsic :: env=>iso_fortran_env
use, source, intrinsic :: env=>iso_fortran_env
use, qualified, intrinsic :: env=>iso_fortran_env
use, as is, intrinsic :: env=>iso_fortran_env

or they could be used as replacements for only

use, intrinsic:: iso_fortran_env, namespace: env
use, intrinsic:: iso_fortran_env, with: env
use, intrinsic:: iso_fortran_env, as is: env
use, intrinsic:: iso_fortran_env, qualified: env

I am sure that with more time I could come up with more examples.

milancurcic commented 4 years ago

@wclodius2 I don't think we're bike shedding. Syntax and choice of keywords are not irrelevant details. They have a direct impact on the programmer, what they're writing, and how they feel about it. I think that the new syntax should:

The optimal solution is not easy to come up with and it's impossible to make everybody happy. All these tedious discussions about words and punctuation and what's intuitive or not are necessary and important part of the work. The more people that provide feedback the more clear we will get about the top candidates.

certik commented 4 years ago

it doesn't allow for the otherwise orthogonal creation of both a namespace as well as unqualified importation of some names.

Neither Python, Julia or Chapel allow that as far as I know with a single statement. @septcolor gave an example in Chapel, in Python you have to do:

import numpy
from numpy import sin

So in Fortran it would become:

use numpy, only:
use numpy, only: sin

I agree with @klausler that it looks a bit confusing. Even without the : it looks weird to me: use numpy, only. The Chapel version, on the other hand, looks good: use numpy only and use numpy only x, but we can't use this without a comma due to ambiguities in the fixed form.

@wclodius2 is right that it might seem like we are "bike shedding", but in order to move this proposal further, the syntax is important. @milancurcic just replied above in similar spirit.

We agreed at the call that we will do a survey at the Fortran Discourse and ask people for preferences.

wclodius2 commented 4 years ago

There are two orthogonal choices in the syntax: first what word to use as the keyword, and second where to put the keyword. So far I have seen the following suggestions for keywords:

namespace - main problem is its length, but users of C++, where namespace behaves like Fortran's use, may find this usage counterintuitive with - main advantage is its length, some find it unintuitive using - similar to use, slightly suggests requiring the module name to access import - used for this in Python, but already a keyword with different semantics employ - a synonym to use source - slightly suggestive of the semantics qualified - one of its meanings is suggestive of the semantics, but not the most commonly used meaning, as long as namespace as with as is - one for renaming the other for non-renaming. What happens if you want to rename to is? ns - an abbreviation for namespace that is similar to nanosecond only - only as a use statement terminator, overloads its current meaning

Are there any names I missed?

I know of three possible places to put the keyword

At the beginning, making its own statement, i.e, keyword[[, module-nature]::] [local-module-name=>]module-name this is what most of the languages cited do

After the use keyword use [[, keyword][, module-nature]::] [local-module-name=>]module-name or use [[, module-nature][, keyword]::] [local-module-name=>]module-name It will be tempting to lump the keyword with intrinsic and nonintrinsic in module-nature, in which case the standard needs to explain that there is no only or rename list.

Replacing the only keyword use[[, module-nature]::] module-name, keyword[:local-module-name] making a third form of a use statement

smeskos commented 4 years ago

@wclodius2

Are there any names I missed?

The word name itself as a verb or the word rename.

However, I find all of the proposed keywords as non-Fortranic way of doing things. With the only exception perhaps of the original proposal of namespace. An example of my personal favorite style of implementing this:

use mathematics, only: cdif=>central_difference
call cdif()
!to
use, namespace, math=>mathematics, only:cdif=>central_difference
call math%cdif()

The keyword namespace will be employed to distinguish between using or not using the name of the module and the symbol => optionally if we want to rename locally the name of the module.

Another alternative to namespace could be modulename, only because the former may cause confusion with the C++ keyword, and why not to reserve it for a possible future similar implementation. Therefore, the alternative to my previous example:

use, modulename, math=>mathematics, only:cdif=>central_difference
call math%cdif()
FortranFan commented 4 years ago

I will request everyone to take a look at my comment in another thread #86, a thread with another proposal that I think is along the same lines as this one. As I suggest therein, I personally would preface NAMESPACE to reflect a formal concept that is waiting to be introduced in the Fortran standard at some later stage in the advancement of this language. Fortran being a language that always holds tremendous promise as a tool for scientists and engineers but which is perpetually trying to "catch up" to the state-of-the-art in technical computing. Meaning the language and its bearers haven't fully caught up yet to the concept of namespace and its benefits though Fortran did a take a big step toward it with MODULEs introduced back in 1991 with the Fortran 90 publication.

In the context of this particular proposal in this thread, I think the search is for a way to decorate module entities suitably during their "consumption" via USE association.

And I think the Fortrannic way will be to introduce both an ATTRIBUTE and a STATEMENT for the same. And where the options gain a FUNCTION-like syntax with optional arguments within parenthesis.

There are several examples of this in the Fortran standard: ALLOCATABLE, BIND, etc. BIND seems to me to be quite apt here for understanding a facility that is both an ATTRIBUTE and a STATEMENT. Note the token BIND in my simple-minded thinking can be viewed as a verb or a command or an instruction which is what seems to be the need here.

So thinking along the same lines, an alternate suggestion will be to use DECORATE as the token:

use, decorate :: utils 
..
call utilsXsavetxt(..)

where X is the separator yet to be decided; it can be % (as in call utils%savetxt(..)) or it might be double-colon (as in call utils::savetxt(..)), etc.

And additional options with (re)naming can be introduced as

use, decorate( name="ut" ) :: utils 
..
call utXsavetxt(..)

With the STATEMENT form, the expected syntax is

use utils
..
decorate :: utils
..
call utilsXsavetxt(..)

Applying the same to @smeskos 's examples above, I would expect the syntax to be

use, decorate(name="math") :: mathematics, only : cdif => central_difference
call mathXcdif()

And if the optional name is not employed,

use, decorate :: mathematics, only : cdif => central_difference
call mathematicsXcdif()

With the example in the J3 paper (https://j3-fortran.org/doc/year/19/19-246.txt), the syntax can look like so:

    use, decorate :: math
    use, decorate( name="np" ) :: numpy
    use, decorate( name="sym") :: sympy
    ...
    e1 = npXsin(npXpi)      ! NumPy expression
    e2 = mathXsin(mathXpi)  ! Built-in Python math expression
    e3 = symXsin(symXpi)    ! SymPy expression

and

    use, decorate :: lapack
    ..
    call lapackXdgeev('N', 'V', n, At, lda, wr, wi, vl, ldvl, vr, ldvr, &
     work, lwork, info)
    ..
    call lapackXdgetrf(n, n, Amt, lda, ipiv, info)
    ..
gronki commented 4 years ago

I find "decorate" concept elegant, except I am not sure why the alternative name is to be put in quotes. In free form, spaces or special characters are not allowed in names afaik, while string literal implies that any characters should be valid. I think that

use, decorate(name = lpk) :: lapack

would be more logical.

When I look at this syntax, it really looks like Fortran to me. Good shot FortranFan. Also because one USE is needed to include one module, while => operator usually appears in constructs that can be used in sequences separated by a comma. So

use, namespace :: np => numpy

naturally encourages user to do

use, namespace :: np => numpy, lpk => lapack

which would be too much of a stretch considering current USE syntax.

I also would agree that using % (so the same operator used to access derived type components) should be very carefully discussed. I would also prefer to have a distinguishment between accessing module and derived type components. :: seems to be another good candidate. While I love Python and in that language no distinguishment makes sense (its an interpreted language), I would say in Fortran I would rather know whether it's a derived type or just a namespace. There is enough confusion as is with parethesis () used both for functions and arrays. Let's not repeat that mistake.

Dominik

sob., 26 wrz 2020 o 19:30 FortranFan notifications@github.com napisał(a):

I will request everyone to take a look at my comment https://github.com/j3-fortran/fortran_proposals/issues/86#issuecomment-554205627in another thread #86 https://github.com/j3-fortran/fortran_proposals/issues/86 that I think is related to this one. As I suggest therein, I personally would preface NAMESPACE to reflect a formal concept to be introduced in the Fortran standard at some later stage in the advancement of this language that always holds tremendous promise as a tool for scientists and engineers but which is perpetually trying to "catch up" to the state-of-the-art in technical computing. Meaning the language and its bearers haven't fully caught up yet to the concept of namespace and its benefits though Fortran took a big step toward it with MODULEs back in 1991 with Fortran 90 publication.

In the context of this particular proposal in this thread, I think the search is for a way to decorate module entities suitably during their "consumption" via USE association.

And I think the Fortrannic way will be to introduce both an ATTRIBUTE and a STATEMENT for the same. And where the options gain a FUNCTION-like syntax with optional arguments within parenthesis.

There are several examples of this in the Fortran standard: ALLOCATABLE, BIND, etc. BIND seems to me to be quite apt here for understanding a facility that is both an ATTRIBUTE and a STATEMENT. Note the token BIND in my simple-minded thinking can be viewed as a verb or a command or an instruction which is what seems to be the need here.

So thinking along the same lines, an alternate suggestion will be to use DECORATE as the token:

use, decorate :: utils ..call utilsXsavetxt(..)

where X is the separator yet to be decided; it can be % (as in call utils%savetxt(..)) or it might be double-colon (as in call utils::savetxt(..)), etc.

And additional options with (re)naming can be introduced as

use, decorate( name="ut" ) :: utils ..call utXsavetxt(..)

With the STATEMENT form, the expected syntax is

use utils .. decorate :: utils ..call utilsXsavetxt(..)

Applying the same to @smeskos https://github.com/smeskos 's examples above, I would expect the syntax to be

use, decorate(name="math") :: mathematics, only : cdif => central_differencecall mathXcdif()

And if the optional name is not employed,

use, decorate :: mathematics, only : cdif => central_differencecall mathematicsXcdif()

With the example in the J3 paper ( https://j3-fortran.org/doc/year/19/19-246.txt), the syntax can look like so:

use, decorate :: math
use, decorate(name="np") :: numpy
use, decorate( name="sym") :: sympy
...
e1 = npXsin(npXpi)      ! NumPy expression
e2 = mathXsin(mathXpi)  ! Built-in Python math expression
e3 = symXsin(symXpi)    ! SymPy expression

and

use, decorate :: lapack
..
call lapackXdgeev('N', 'V', n, At, lda, wr, wi, vl, ldvl, vr, ldvr, &
 work, lwork, info)
..
call lapackXdgetrf(n, n, Amt, lda, ipiv, info)
..

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/j3-fortran/fortran_proposals/issues/1#issuecomment-699524583, or unsubscribe https://github.com/notifications/unsubscribe-auth/AC4NA3O3N7FNNZ3GMNFHHO3SHYQMNANCNFSM4JBFRGNA .

milancurcic commented 4 years ago

I also like @FortranFan's idea of specifying the namespace name in parentheses following the keyword. Also with @gronki that the new name shouldn't be a string literal.

I don't like the word "decorate" here. To me it means to add functionality to something which I don't think is what we're doing.

FortranFan commented 4 years ago

@gronki, @milancurcic ,

I'm ok with the synonym to be not a string literal i.e., a default-char-constant-expr per the standard. I had suggested as much based on what I thought I had heard previously with certain compiler implementations and how they parse the FUNCTION-like approach with the use of parenthesis in ATTRIBUTEs and STATEMENTs. This is where an implementation or two, as suggested by @certik, will come in handy: it can help work through such options.

@milancurcic ,

Re: "I don't like the word "decorate" here. To me it means to add functionality to something which I don't think is what we're doing.":

Then, in the dictionary sense of the term, this is nothing but decoration. That's why I suggested that token. It seems to better capture the essence of the functionality being proposed here than all the alternatives suggested upthread.

But if it's too verbose, another alternative is ADORN.

By the way, I had thought of DISTINGUISH and EMBELLISH also because in a sense with the PI example shown above with Python packages, this proposal is in a way seeking an easier way to distinguish/embellish the entities from each other in a given scope. It seemed even more verbose or negative-sounding, so I decided against it.

Now, if people starting getting too much into further nits with the choice of the word, that will confirm @wclodius2 's point earlier about the bikeshedding here.

gronki commented 4 years ago

Yeah perharps the choice of a word is a bit of a detail. From my perspective as a non-native English speaker, the word should be commonly used in international English (never seen "adorn" before) and not to be confused with something else (like IMPORT proposed in another context). I am sure there is one than more word that fits this criteria :)

Dominik

niedz., 27 wrz 2020 o 19:02 FortranFan notifications@github.com napisał(a):

@gronki, @milancurcic ,

I'm ok with the synonym to be not a string literal i.e., a default-char-constant-expr per the standard. I had suggested as much based on what I thought I had heard previously with certain compiler implementations and how they parse the FUNCTION-like approach with the use of parenthesis in ATTRIBUTEs and STATEMENTs. This is where an implementation or two, as suggested by @certik, will come in handy: it can help work through such options.

@milancurcic ,

Re: "I don't like the word "decorate" here. To me it means to add functionality to something which I don't think is what we're doing.":

note this proposal is indeed adding a functionality, albeit it is in the form of an adornment or an embellishment. What might previously be a use-associated entity FOO from MY_MOD module will no longer have its first-class (or an independent) identity that it has with current standard. Meaning, there can no longer be a reference to FOO in that scope. It must be "adorned" as something like MY_MOD::FOO (or MY_MOD%FOO, depending on the separator chosen.)

Then, in the dictionary sense of the term, this is nothing but decoration. That's why I suggested that token. It seems to better capture the essence of the functionality being proposed here than all the alternatives suggested upthread.

But if it's too verbose, another alternative is ADORN. But if people starting getting into further nits with the choice of the word, that will confirm @wclodius2 's point earlier about the bikeshedding here.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or unsubscribe.

milancurcic commented 4 years ago

@FortranFan Thank you, only after your detailed explanation I was able to understand--you're not decorating the module itself, but the public entities in the module. Now it makes more sense.

I'd still advise against it because of how easily it can be confused with decorating as a software design pattern. For example, if I was teaching this concept, I'd have to caveat it with something like "If you've used decorators in other languages before, be careful--this does something completely different", and then refer to it as "namespace" in the rest of the material. :)

This is also a good example of why I think the choice of the word is important.

FortranFan commented 4 years ago

@septcolor wrote:

.. And one more possibility may be this form? .. .. USE hitechlib AS ht

As mentioned upthread, punctuation or a separator between conjunctions is needed to support the 2 sources forms in Fortran, and that's why this does not work.

certik commented 4 years ago

Thanks everybody for your input and making progress on this issue.

@septcolor raises an important thing to consider: #86 (nested modules). As posted there, this might work:

use, namespace :: mylib%a
...
call mylib%a%something()

I like the :: option instead of % also, but I don't know if it will work syntax wise for nested modules:

use, namespace :: mylib::a
...
call mylib::a::something()

Don't know if there could be issues parsing it.

Another issue to consider is nested modules (proposed feature as in #86) versus modules using other modules (existing feature) with regards to syntax and importing. E.g., does call mylib::a::something() work for both a being a nested module, versus a being used inside mylib?

wclodius2 commented 4 years ago

There seems to have been a consensus that there should be a poll/vote on the preferred syntax. As there has been a significant pause in postings on this issue, I think it is an appropriate to summarize our current syntactic options to prompt more suggestions for options. There are four orthogonal choices in the syntax:

  1. What word to use as the keyword
  2. Where to put the keyword
  3. How to do module renaming
  4. What to use as the accessor "operator"

What word to use

So far I have seen the following suggestions for keywords:

Are there any names I missed? With this many options it might be best to do a ranked choice vote.

Where to put the keyword

I know of three possible places to put the keyword

  1. At the beginning, making its own statement, i.e, keyword[[, module-nature]::] .... This is what most of the languages cited do.
  2. After the use keyword: use [[, keyword][, module-nature]::] ... or use [[, module-nature][, keyword]::] .... It will be tempting to lump the keyword with intrinsic and nonintrinsic in module-nature, in which case the standard needs to explain that there is no only or rename list.
  3. Replacing the only keyword: use[[, module-nature]::] module-name, keyword[:local-module-name] making a third form of a use statement.

How to rename modules

I have noted three ways to do module renaming:

  1. Use a syntax based on the rename list of the use statement [local-module-name=>]module-name, e.g.,
    • keyword[[, module-nature]::] [local-module-name=>]module-name
    • use [[, keyword][, module-nature]::] [local-module-name=>]module-name
    • use [[,module-nature]::][local-module-name=>]module-name, keyword
  2. After the colon after the module name where the keyword replaces only: use [[,module-nature]::]module-name, keyword[: local-module-name]
  3. In a parenthesized rename after the keyword
    • keyword[([name=]local-module-name)][[, module-nature]::] module-name
    • use [[, keyword[([name=]local-module-name)]][, module-nature]::] module-name
    • use [[,module-nature]::]module-name, keyword[([name=]local-module-name)]

What to use as accessor operator

I have noted two suggestions for the accessor operator

  1. %, used as the accessor for derived types
  2. ::, used extensively in the specification-part, but not in the execution-part of Fortran programs/subprograms. The main question is would its use cause what is intended to be an executable statement, to be interpreted as a specification statement, i.e., could a module name be the same as the start of a specification statement.

In principle other characters could also be used: backtick, ~, @, ^, |, and \ are ASCII characters not used by Fortran, and, I believe, not used by the common pre-processors.

FWIW I tend to prefer the shorter keywords, but dislike overloading the meaning of "only" and "import". So my first preference is with followed by using and adorn. I believe modifying the use statement to incorporate the keyword, will more complicate the standard than having a keyword statement, so I prefer a keyword statement. Because I don't want a modified use statement, I don't want the rename after the colon after the keyword. I don't have strong feelings about keyword[([name=]local-module-name)] versus [local-module-name=>]module-name. I prefer the accessor to be the same as for derived types, i.e., %, but :: would also be acceptable.

Edit: Formatting by @milancurcic for readability

milancurcic commented 4 years ago

Thank you for the summary @wclodius2, it's very helpful. Here's my current preference:

  1. What word to use: as (renaming) and as is (non-renaming)
  2. Where to put the keyword: Option 3: use[[, module-nature]::] module-name, as[: local-module-name]
  3. How to rename modules: use[[, module-nature]::] module-name, as is
  4. What to use as accessor operator: Aesthetically I like :: best. If it's problematic due to issues you raise, I like either % or @. Others I don't like.

Examples:

Addendum to the syntax proposal which would allow orthogonal imports as @klausler suggested: It's possible to use the only keyword following the as: local-module-name, so the syntax becomes:

use[[, module-nature]::] module-name, as[: local-module-name][, only: [local-entity-name =>] entity-name]

Example:

use stdlib_stats, as: stats, only: mean, var

This statement would import stdlib_stats as a stats namespace (with all public entities therein available via the namespace), and also import mean and var into the global namespace.

To prevent writing confusing code, as would have to appear before only if both are used. So

use stdlib_stats, only: mean, var, as: stats

shouldn't be allowed IMO.

milancurcic commented 4 years ago

I didn't think about that. It does seem like the most elegant solution. Simply make it available as a namespace if you don't need it renamed. It's backward compatible because, as you say, it has been impossible to reference a module name after a use statement. I like it.

wclodius2 commented 4 years ago

First Fortran module names tend to be long to reduce the possibility of name clashes so most of the time users would find renaming useful though it could be

use[(name=local-module-name)][[,module-nature]::]module-name..;.

Second some users will want the processor to enforce the use of the module name as a qualifier which in turn requires the use of a different syntax to let the processor know that that is a requirement.

milancurcic commented 4 years ago

some users will want the processor to enforce the use of the module name as a qualifier which in turn requires the use of a different syntax to let the processor know that that is a requirement.

Indeed, once you can namespace, simple and common names will proliferate in modules and the user should have a way to not have them pollute the global namespace.

certik commented 4 years ago

@klausler That seems to be a very similar idea to what I proposed above https://github.com/j3-fortran/fortran_proposals/issues/1#issuecomment-699120529, but I thought you didn't like it. Are you proposing exactly the table in that comment, or are you proposing the following table (in other words, do you want to allow use A, only: or not):

Case Python Julia Chapel Fortran
1. import A import A use A only use A
2. import A as B import A as B use A as B only use B => A
3. from A import x using A: x use A only x use A, only: x
4. from A import x as y import A: x as y use A only x as y use A, only: y => x
5. from A import * using A use A use A

Furthermore, in all cases 1.-5., the module name A (or B in 2.) will always be created as a namespace, in addition to importing all the symbols from it in 1., 2. and 5. (and only x or y in 3. and 4.).

If the above is what you are proposing, I can see all kinds of extensions in the compiler, for example with an option the compiler can start warning (by supplying -Wimplicit-use) if you do use A but use any implicitly imported symbol from the module (in case 1.), and if you want to use case 5. and not get a warning, you can do use A, only: *. The syntax would be natural, and I would enable that -Wimplicit-use warning option for my codes (I currently never use use A anyway). In this case, it would make sense to consider adding the syntax use A, only: * into this proposal also, to make it standardized: in other words, use A, only: * would be equivalent to use A, but the compiler would only warn if you use some symbol implicitly in the latter case. That should be strictly backwards compatible, and yet doing exactly what I would like. People who don't like this (or for older codes) would just not enable the -Wimplicit-use compiler warning.

certik commented 4 years ago

Ok, so to summarize, you are proposing this:

Case Python Julia Chapel Fortran
1. import A import A use A only use A, only:
2. import A as B import A as B use A as B only use B => A, only:
3. from A import x using A: x use A only x use A, only: x
4. from A import x as y import A: x as y use A only x as y use A, only: y => x
5. from A import * using A use A use A

Where the cases 1. and 2. are exactly equivalent to Python, but cases 3., 4. and 5. are a "superset" of Python: they import the x, y or all symbols as in Python respectively, but also in addition make the module name A available as a namespace in Fortran (which does not happen in Python).

I like this proposal.

certik commented 4 years ago

Thanks Peter. My goal is to get it pre-approved by the committee, saying "yes, we want this feature, as long as all the issues can be satisfactorily resolved". The minute it does, I am sure multiple people from the community will help. Obviously nobody wants to put in weeks of work if the committee decides they don't want this feature in the first place.

I plan to prototype this in a compiler.

FortranFan commented 4 years ago

@klausler wrote Oct. 1, 2020 6:48 PM EDT:

The harder part of this proposal remains to be discussed, too. ..

I agree.

As I alluded to earlier, Fortran language can do better by gaining the formal concept of namespaces. Ideally, features such as this are best handled as part of that effort.

Considering the complexities and constraints involved with piecemeal attempts, a prototype implementation for the formal namespace concept itself will be nice. The aspects such as this thread can be subparts of such an initiative.

certik commented 4 years ago

I personally feel we don't need namespaces, but I agree with Vipul that we should keep it in mind and not close doors by introducing something that would make it very hard to introduce namespaces later if the community wishes that.

Modules and a well designed "import" is what I personally would like to see. Fortran is very close.

@septcolor regarding who can contribute: I strongly encourage you and anyone else to contribute. The committee and the community is composed of both users and compiler vendors / experts, and we need both to collaborate on new features. Leaving things just to compiler vendors, or just to users to design is not optimal, we need a healthy collaboration of both groups.

FortranFan commented 4 years ago

@wclodius2 wrote Oct. 1, 2020

There seems to have been a consensus that there should be a poll/vote on the preferred syntax. As there has been a significant pause in postings on this issue, I think it is an appropriate to summarize our current syntactic options to prompt more suggestions for options. There are four orthogonal choices in the syntax:

What word to use as the keyword ..

If there are folks who aren't enthused by any of the keywords thus far, here's another one that can perhaps considered for the poll? PREFIX:

use, prefix(ut) :: utils, only : savetxt
..
call utXsavetxt(..)
aradi commented 2 years ago

I think, the idea with prefix is a really nice one. But, maybe prefixed (as adjective) is more aligned with what we have already, e.g.

use, intrinsic, prefixed :: iso_fortran_env        ! if entire module name is used as prefix
use, intrinsic, prefixed(ife) :: iso_fortran_env  ! if specified prefix is used
beddalumia commented 2 years ago
  • use stdlib_stats, as: stats
  • use stdlib_stats, as is

I would find it rather confusing, not the first one, which I think is neat, but the second: "as is" makes me think about "as given" / "raw" / "as provided", so equivalent to the current behavior withuse stdlib_stats (which I hope you want to preserve: there are cases where one wants a namespace, there are cases where it just adds unnecessary verbosity, that's why python offers also the from x import z syntax).

What about

instead?

I find it very "natural-english-alike", which is imo what Fortran has always striven for...

shahmoradi commented 2 years ago

How about

use, intrinsic, namespace :: iso_fortran_env        ! if the entire module name is used as a prefix
use, intrinsic, namespace :: ife => iso_fortran_env  ! if the specified prefix is used