Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change `extern "ABI"` to `extern<ABI>` or `extern ABI` or `extern(ABI)` #156

Closed
wants to merge 2 commits into from

Conversation

Projects
None yet
@glaebhoerl
Copy link
Contributor

glaebhoerl commented Jul 5, 2014

@lilyball

This comment has been minimized.

Copy link
Contributor

lilyball commented Jul 5, 2014

I don't see the benefit to this. The supported ABIs for a function type are determined by the compiler, not by the library, and so having to use an enumeration (which would presumably be defined in the library using lang items to identify it to the compiler) for ABI just strikes me as odd.

The only proposed benefit is the ability to abstract over the ABI of a function, but we could support this today merely by having the compiler provide automatic generation of function shims that expose a function from one ABI as if it were another. In fact, we basically already have this through closures; if you accept a closure value, function values will be implicitly wrapped in closures. I haven't tested to see how that handles ABI but I assume the compiler does that regardless of the function ABI.

An unlisted drawback is that providing an enumeration like this is polluting the prelude with yet more stuff. We try to avoid putting values in the prelude (for the most part it's just traits), but for extern<ABI> to be useful, we'd have to put the enumeration variants in the prelude as well. Not doing so makes it even more confusing how to specify a function of a different ABI and makes it harder to teach people how it's supposed to work.

@glaebhoerl

This comment has been minimized.

Copy link
Contributor Author

glaebhoerl commented Jul 6, 2014

Just to be clear, this proposal is only about changing the syntax we currently use, not any kind of semantic change (exposing an enum, adding it to the prelude, etc.). It only creates the opportunity for later adding that kind of thing, if we want to.

Even if we never actually end up doing that, conceptually the ABI specifier is still much more like an enumeration member than a string. There is a limited list of options and you choose one of them; it's not free-form. Of course, making a breaking change just for this kind of conceptual consistency may not be worthwhile.

I'm not particularly attached to this idea, and I have no idea whether it might have any practical benefit myself. I just figured I would write it up because it's interesting, and one of those rare RFCs which is small.

The supported ABIs for a function type are determined by the compiler, not by the library, and so having to use an enumeration (which would presumably be defined in the library using lang items to identify it to the compiler) for ABI just strikes me as odd.

The list-of-variants would probably have to come from the compiler in some fashion.

@huonw

This comment has been minimized.

Copy link
Member

huonw commented Jul 7, 2014

I definitely prefer using identifiers (rather than strings) for closed classes this; as you say, strings feel free-form.

@o11c

This comment has been minimized.

Copy link
Contributor

o11c commented Jul 8, 2014

I prefer strings, because who's to say that one day someone won't write a compiler plugin that does extern "Nimrod" or extern "Clay"?

@huonw

This comment has been minimized.

Copy link
Member

huonw commented Jul 8, 2014

@o11c being an identifier doesn't prohibit other names, i.e. the parser etc. could handle extern<Foo> and just have some later pass check the Foo.

@pcwalton

This comment has been minimized.

Copy link
Contributor

pcwalton commented Jul 9, 2014

How does this interact with macro hygiene?

@bstrie

This comment has been minimized.

Copy link
Contributor

bstrie commented Jul 11, 2014

I missed that this was not proposing an enum for all possible ABIs. Even if we could create such an enum sometime in the future, I highly doubt that we ever would, as adding names to the prelude is both gross and backwards-incompatible.

So really this is just strictly a syntactic change. extern "C" is definitely gunky, but has precedent from C++. Maybe it's so minor that it doesn't matter breaking with precedent. I don't like extern<C>, as pretending there's some sort of real parameterization going on is just as misleading as having it being a string. extern C looks okay, I suppose. Mostly I'm ambivalent.

@Ericson2314

This comment has been minimized.

Copy link
Contributor

Ericson2314 commented Jul 15, 2014

+1 identifiers seem much more appropriate than string literals.

@blaenk

This comment has been minimized.

Copy link
Contributor

blaenk commented Jul 20, 2014

I'm in favor of this change, since like @huonw says, strings feel free-form when they're clearly not. +1

EDIT: I think I prefer the extern<ABI> notation as it makes it clearer that the ABI identifier is part of the extern declaration.

// what's system?
let fptr: extern system fn() -> int = new_int;

// clearer IMO
let fptr: extern<system> fn() -> int = new_int;
@glaebhoerl

This comment has been minimized.

Copy link
Contributor Author

glaebhoerl commented Jul 20, 2014

I think extern<ABI> would be a good idea if and only if the idea of ABI as a type argument is actually a good intuition. (I'm not completely sure whether it is; I just think it might be.)

If it's not, then there'd be no point in changing from one misleading intuition to another misleading intuition. Either extern ABI, or perhaps extern(ABI) as another possibility (to make it clearer that they belong together), would be a better option in that case.

@pczarn

This comment has been minimized.

Copy link

pczarn commented Jul 20, 2014

I consider the association with type arguments to be good intuition. A close analogy within the type system seems to be fn foo<T: Integer>(bar: T) where T could be passed as for example i16 or i64, but that's a low level detail. Moreover, parameterization over the ABI is intriguing.

Still, extern "C" is common in C++. And the extern Rust syntax is lightweight. So each alternative has a merit.

@liigo

This comment has been minimized.

Copy link
Contributor

liigo commented Jul 20, 2014

-1. Looks weird syntax, where ABI is neither keywords nor library defined names.

extern "C" is the syntax that C++ uses. It's OK, especially for FFI.

@alexchandel

This comment has been minimized.

Copy link

alexchandel commented Jul 28, 2014

How does

extern rust-call fn call(...);

compare to

extern "rust-call" fn call(...);

?

Requiring ABI names to be identifiers may limit what compiler plugins one could provide. Also, it may create the illusion of collision with or shadowing of other identifiers in scope.

@glaebhoerl

This comment has been minimized.

Copy link
Contributor Author

glaebhoerl commented Jul 28, 2014

FWIW I'm leaning toward

extern(rust-call) fn call(...);

syntax iff the extern<> analogy is considered to not be sensible.

@huonw

This comment has been minimized.

Copy link
Member

huonw commented Jul 28, 2014

Why not RustCall, rustcall or rust_call (etc.)?

@glaebhoerl glaebhoerl changed the title Change `extern "ABI"` to `extern<ABI>` or `extern ABI` Change `extern "ABI"` to `extern<ABI>` or `extern ABI` or `extern(ABI)` Jul 28, 2014

@alexchandel

This comment has been minimized.

Copy link

alexchandel commented Jul 30, 2014

So the choices are:

#[link(name = "c")]
extern "C"
{
    fn printf(arg: *const u8, ...) -> i32;
}

#[link(name = "c")]
extern C
{
    fn printf(arg: *const u8, ...) -> i32;
}

#[link(name = "c")]
extern(C)
{
    fn printf(arg: *const u8, ...) -> i32;
}

#[link(name = "c")]
extern<C>
{
    fn printf(arg: *const u8, ...) -> i32;
}

Unless the types C, fastcall, Rust, etc, or something like enum ABI {C, Rust, RustCall, cdecl, fastcall, ...} were actually provided somewhere, the syntax looks misfitting. But since arbitrary string literals aren't valid calling conventions, a change is appropriate.

It's similar to what's already provided in syntax::abi, enum Abi { C, Rust, RustCall, Cdecl, Fastcall, ...}, except syntax::abi::Abi changes the names to fit Rust's CamelCase. This may or may not be appropriate for all, e.g. extern(Fastcall).

@brendanzab

This comment has been minimized.

Copy link
Member

brendanzab commented Jul 31, 2014

I like extern<RustCall> fn ....

A counter to the argument against extensibility could be that type parameter is an uninhabited enum, ie. enum RustCall {}. Therefore using the parametrization syntax makes sense.

@brson

This comment has been minimized.

Copy link
Contributor

brson commented Sep 3, 2014

Although the syntax is not attractive, it's not 'common', there's existing precedent, and the string syntax makes it clear these are implementation- and platform-specific and not keywords or 'normal' identifiers. We'll keep this as-is. Thank you.

Meeting discussion

@brson brson closed this Sep 3, 2014

withoutboats pushed a commit to withoutboats/rfcs that referenced this pull request Jan 15, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.