Promote "primitive" types to enums in extensions

It is a common practice in C to assign to integer (int, int16, int64, etc.) typed variables “constant" values declared in enums. In swift, it is in fact possible to do that by using enums' “rawValue” property. When importing structs from C into swift, we even get some fields declared with an integer type, but expecting the assignment of a “constant” declared inside an enum. Of course, this is error prone, it is “old-style” programming and very confusing for newcomers. To solve this issue, my proposal is to be able to create extensions that promote certain fields within a class or struct to enums.

For instance, let’s take these sample C struct and enum:

struct Card {
  int suit;
  int rank;
};

typedef enum {HEARTS, DIAMONDS, CLUBS, SPADES} CardSuit;

(Note: I understand that above code follows a bad programming practice, yet it is widely common)

It should be imported into swift as follows:

struct Card {
  suit:Int
  value:Int
}

enum CardSuit : Int {
  case Hearts, Diamonds, Clubs, Spades
}

Now, I propose to be able to create an extension as follows:

extension Card {
  #enumvalue(suit:CardSuit)
}

From this moment on, the suit field should only receive CardSuit values, thus not requiring the use of raw values for assignments.

These extensions should also be of great interest for people using CoreData, since it is not possible to declare enums in models. Therefore, to declare enums, it is necessary to declare integer values, and then use the “unsafe”, “unexpressive" approach explained before.

Note that the proposal intends to only support promotions from integer values to enum values, but, for example, it could also be extended to string values.

Finally, it could be appropriate to extend this proposal to redeclare func’s signatures, in order to promote certain parameters to enum values.

Best,

Carlos.

I would rather have a syntax that mirrors the way Protocol does it.

struct Card {
        suit:enum<CardSuit>
        value:Int
}

or we could change it so this only excepts the enum itself unless
you explicitly cast from a Int or another enum:

struct Card {
        suit:CardSuit
        value:Int
}

···

*___________________________________*

*James⎥Head Of CEO*

*james@supmenow.com <james@supmenow.com>⎥supmenow.com <http://supmenow.com>*

*Sup*

*Runway East *

*10 Finsbury Square*

*London*

* EC2A 1AF *

On Thu, Mar 24, 2016 at 5:41 PM, Carlos Rodríguez Domínguez < swift-evolution@swift.org> wrote:

It is a common practice in C to assign to integer (int, int16, int64,
etc.) typed variables “constant" values declared in enums. In swift, it is
in fact possible to do that by using enums' “rawValue” property. When
importing structs from C into swift, we even get some fields declared with
an integer type, but expecting the assignment of a “constant” declared
inside an enum. Of course, this is error prone, it is “old-style”
programming and very confusing for newcomers. To solve this issue, my
proposal is to be able to create extensions that promote certain fields
within a class or struct to enums.

For instance, let’s take these sample C struct and enum:

struct Card {
        int suit;
        int rank;
};

typedef enum {HEARTS, DIAMONDS, CLUBS, SPADES} CardSuit;

(Note: I understand that above code follows a bad programming practice,
yet it is widely common)

It should be imported into swift as follows:

struct Card {
        suit:Int
        value:Int
}

enum CardSuit : Int {
        case Hearts, Diamonds, Clubs, Spades
}

Now, I propose to be able to create an extension as follows:

extension Card {
        #enumvalue(suit:CardSuit)
}

From this moment on, the suit field should only receive CardSuit values,
thus not requiring the use of raw values for assignments.

These extensions should also be of great interest for people using
CoreData, since it is not possible to declare enums in models. Therefore,
to declare enums, it is necessary to declare integer values, and then use
the “unsafe”, “unexpressive" approach explained before.

Note that the proposal intends to only support promotions from integer
values to enum values, but, for example, it could also be extended to
string values.

Finally, it could be appropriate to extend this proposal to redeclare
func’s signatures, in order to promote certain parameters to enum values.

Best,

Carlos.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Well, I propose the “#” syntax to be consistent with other proposals that intend to provide compilation-related code. In this case, the proposal is just a way to provide an indication that a certain field within a struct or class should be enforced to be a value of a certain enum, not just a plain integer, by the compiler. Anyhow, I think many different sintaxis could be elaborated. For example, another possible syntax could imply reusing the typealias expression:

extension Card{
  typealias suit:CardSuit = suit:Int
}

However, I assume that using this syntax it should be possible to directly assign to the suit field both an integer or a CardSuit.

···

El 24 mar 2016, a las 18:43, James Campbell <james@supmenow.com> escribió:

I would rather have a syntax that mirrors the way Protocol does it.

struct Card {
        suit:enum<CardSuit>
        value:Int
}

or we could change it so this only excepts the enum itself unless you explicitly cast from a Int or another enum:

struct Card {
        suit:CardSuit
        value:Int
}

___________________________________

James⎥Head Of CEO

james@supmenow.com <mailto:james@supmenow.com>⎥supmenow.com <http://supmenow.com/&gt;
Sup

Runway East >

10 Finsbury Square

London

> EC2A 1AF

On Thu, Mar 24, 2016 at 5:41 PM, Carlos Rodríguez Domínguez <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
It is a common practice in C to assign to integer (int, int16, int64, etc.) typed variables “constant" values declared in enums. In swift, it is in fact possible to do that by using enums' “rawValue” property. When importing structs from C into swift, we even get some fields declared with an integer type, but expecting the assignment of a “constant” declared inside an enum. Of course, this is error prone, it is “old-style” programming and very confusing for newcomers. To solve this issue, my proposal is to be able to create extensions that promote certain fields within a class or struct to enums.

For instance, let’s take these sample C struct and enum:

struct Card {
        int suit;
        int rank;
};

typedef enum {HEARTS, DIAMONDS, CLUBS, SPADES} CardSuit;

(Note: I understand that above code follows a bad programming practice, yet it is widely common)

It should be imported into swift as follows:

struct Card {
        suit:Int
        value:Int
}

enum CardSuit : Int {
        case Hearts, Diamonds, Clubs, Spades
}

Now, I propose to be able to create an extension as follows:

extension Card {
        #enumvalue(suit:CardSuit)
}

From this moment on, the suit field should only receive CardSuit values, thus not requiring the use of raw values for assignments.

These extensions should also be of great interest for people using CoreData, since it is not possible to declare enums in models. Therefore, to declare enums, it is necessary to declare integer values, and then use the “unsafe”, “unexpressive" approach explained before.

Note that the proposal intends to only support promotions from integer values to enum values, but, for example, it could also be extended to string values.

Finally, it could be appropriate to extend this proposal to redeclare func’s signatures, in order to promote certain parameters to enum values.

Best,

Carlos.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

Why can’t you do this? No raw values required, except to initialize the enums.

struct Card {
    enum Suit : Int { case Hearts, Spades, Diamonds, Clubs }
    enum Rank : Int { case Ace, Two, Three, Four, Five, Six, Seven, Eight, Nine, Jack, Queen, King }

    let suit : Suit
    let rank : Rank

    init?(suit: Int, rank: Int) {
        guard let suit = Suit(rawValue: suit),
              let rank = Rank(rawValue: rank) else {
                return nil
        }
        self.suit = suit
        self.rank = rank
    }
}

let firstCard = Card(suit: 0, rank: 3)
let secondCard = Card(suit: 3, rank: 2)
firstCard?.rank // returns Four
secondCard?.suit // returns Clubs

···

On Mar 24, 2016, at 11:18 AM, Carlos Rodríguez Domínguez via swift-evolution <swift-evolution@swift.org> wrote:

Well, I propose the “#” syntax to be consistent with other proposals that intend to provide compilation-related code. In this case, the proposal is just a way to provide an indication that a certain field within a struct or class should be enforced to be a value of a certain enum, not just a plain integer, by the compiler. Anyhow, I think many different sintaxis could be elaborated. For example, another possible syntax could imply reusing the typealias expression:

extension Card{
  typealias suit:CardSuit = suit:Int
}

However, I assume that using this syntax it should be possible to directly assign to the suit field both an integer or a CardSuit.

b

On Thu, Mar 24, 2016 at 5:41 PM, Carlos Rodríguez Domínguez <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
It is a common practice in C to assign to integer (int, int16, int64, etc.) typed variables “constant" values declared in enums. In swift, it is in fact possible to do that by using enums' “rawValue” property. When importing structs from C into swift, we even get some fields declared with an integer type, but expecting the assignment of a “constant” declared inside an enum. Of course, this is error prone, it is “old-style” programming and very confusing for newcomers. To solve this issue, my proposal is to be able to create extensions that promote certain fields within a class or struct to enums.

For instance, let’s take these sample C struct and enum:

struct Card {
        int suit;
        int rank;
};

typedef enum {HEARTS, DIAMONDS, CLUBS, SPADES} CardSuit;

(Note: I understand that above code follows a bad programming practice, yet it is widely common)

It should be imported into swift as follows:

struct Card {
        suit:Int
        value:Int
}

enum CardSuit : Int {
        case Hearts, Diamonds, Clubs, Spades
}

Now, I propose to be able to create an extension as follows:

extension Card {
        #enumvalue(suit:CardSuit)
}

From this moment on, the suit field should only receive CardSuit values, thus not requiring the use of raw values for assignments.

These extensions should also be of great interest for people using CoreData, since it is not possible to declare enums in models. Therefore, to declare enums, it is necessary to declare integer values, and then use the “unsafe”, “unexpressive" approach explained before.

Note that the proposal intends to only support promotions from integer values to enum values, but, for example, it could also be extended to string values.

Finally, it could be appropriate to extend this proposal to redeclare func’s signatures, in order to promote certain parameters to enum values.

Best,

Carlos.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

The key of this proposal is that the struct/class should come from outside any swift source code, that is, either imported by the compiler from C, or auto-generated from any external tool (i.e., a CoreData autogenerated class from a graphically specified data model). Of course, in well written structures (as specified by Paul Ossenbruggen) we shouldn’t have any need for this proposal. However, many C structures make use of a raw type instead of an enum type, but specifying (through the associated documentation, not by any type enforcement) that only a set of enum values are allowed. Consequently, the resulting code making use of those structures becomes highly error prone, and, particularly in swift, very “old-style” code and difficult to understand for newcomers.

Again, I would like to highlight that my proposal intends to avoid as much as possible the use of enums’ raw values.

···

El 25 mar 2016, a las 6:42, Paul Ossenbruggen <possen@gmail.com> escribió:

Why can’t you do this? No raw values required, except to initialize the enums.

struct Card {
    enum Suit : Int { case Hearts, Spades, Diamonds, Clubs }
    enum Rank : Int { case Ace, Two, Three, Four, Five, Six, Seven, Eight, Nine, Jack, Queen, King }

    let suit : Suit
    let rank : Rank

    init?(suit: Int, rank: Int) {
        guard let suit = Suit(rawValue: suit),
              let rank = Rank(rawValue: rank) else {
                return nil
        }
        self.suit = suit
        self.rank = rank
    }
}

let firstCard = Card(suit: 0, rank: 3)
let secondCard = Card(suit: 3, rank: 2)
firstCard?.rank // returns Four
secondCard?.suit // returns Clubs

On Mar 24, 2016, at 11:18 AM, Carlos Rodríguez Domínguez via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Well, I propose the “#” syntax to be consistent with other proposals that intend to provide compilation-related code. In this case, the proposal is just a way to provide an indication that a certain field within a struct or class should be enforced to be a value of a certain enum, not just a plain integer, by the compiler. Anyhow, I think many different sintaxis could be elaborated. For example, another possible syntax could imply reusing the typealias expression:

extension Card{
  typealias suit:CardSuit = suit:Int
}

However, I assume that using this syntax it should be possible to directly assign to the suit field both an integer or a CardSuit.

b

On Thu, Mar 24, 2016 at 5:41 PM, Carlos Rodríguez Domínguez <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
It is a common practice in C to assign to integer (int, int16, int64, etc.) typed variables “constant" values declared in enums. In swift, it is in fact possible to do that by using enums' “rawValue” property. When importing structs from C into swift, we even get some fields declared with an integer type, but expecting the assignment of a “constant” declared inside an enum. Of course, this is error prone, it is “old-style” programming and very confusing for newcomers. To solve this issue, my proposal is to be able to create extensions that promote certain fields within a class or struct to enums.

For instance, let’s take these sample C struct and enum:

struct Card {
        int suit;
        int rank;
};

typedef enum {HEARTS, DIAMONDS, CLUBS, SPADES} CardSuit;

(Note: I understand that above code follows a bad programming practice, yet it is widely common)

It should be imported into swift as follows:

struct Card {
        suit:Int
        value:Int
}

enum CardSuit : Int {
        case Hearts, Diamonds, Clubs, Spades
}

Now, I propose to be able to create an extension as follows:

extension Card {
        #enumvalue(suit:CardSuit)
}

From this moment on, the suit field should only receive CardSuit values, thus not requiring the use of raw values for assignments.

These extensions should also be of great interest for people using CoreData, since it is not possible to declare enums in models. Therefore, to declare enums, it is necessary to declare integer values, and then use the “unsafe”, “unexpressive" approach explained before.

Note that the proposal intends to only support promotions from integer values to enum values, but, for example, it could also be extended to string values.

Finally, it could be appropriate to extend this proposal to redeclare func’s signatures, in order to promote certain parameters to enum values.

Best,

Carlos.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

(Please, take a look at the proposal named "[swift-evolution] Promote "primitive" types to enums in extensions” in order to understand the intention of my proposal as a whole)

This proposal intends to allow developers to rewrite func signatures to better adapt certain imported C functions to swift. For instance, the function to create a POSIX socket has a C signature like this:

int socket(int domain, int type, int protocol);

In swift, it is currently imported like this:

func socket(_: Int32, _: Int32, _: Int32) -> Int32

However, by documentation, the first parameter should be one of a set of constants beginning with PF_. The second one should be either SOCK_STREAM, SOCK_DGRAM or SOCK_RAW. The third one should be a constant specifying the protocol to use. Finally, the result could be either -1 (to indicate an error) or another integer to indicate that a socket descriptor has been returned.

As you can observe, that old-style signature is highly error prone, does not comply with swift guidelines, it is difficult to understand, etc. My opinion is that there should be some syntax to rewrite the signature to avoid those issues. For instance, a possible syntax could be:

#mapsignature(socket(_:,_:,_:)->Int32)
func socket(domain:SocketDomain, type:SocketType, protocol:SocketProtocol) -> socket_t? {
  let result = socket(domain.rawValue, type.rawValue, protocol.rawValue)
  if result == -1 {
    return nil
  }
  else{
    return result
  }
}

Note that the compiler should enforce a function call to the original function that we are rewriting.

After a rewriting has happened, three options may be considered: either to allow the original function to be called, to avoid the original function to be called (through a compiler error with a fix-it) or to emit a warning, advising the developer to adopt the rewritten signature.

Anyhow, this proposal should allow a greatly increased interoperability between old style code and swift, which, in my opinion, is quite “forced” right now.

I think I may be similarly misunderstanding your proposal; your intention then is to import the type as an enum with raw value (to facilitate the conversion to/from the C code) but without exposing that raw value on the Swift side?

In that case I think I’m in favour.

···

On 25 Mar 2016, at 09:56, Carlos Rodríguez Domínguez via swift-evolution <swift-evolution@swift.org> wrote:

The key of this proposal is that the struct/class should come from outside any swift source code, that is, either imported by the compiler from C, or auto-generated from any external tool (i.e., a CoreData autogenerated class from a graphically specified data model). Of course, in well written structures (as specified by Paul Ossenbruggen) we shouldn’t have any need for this proposal. However, many C structures make use of a raw type instead of an enum type, but specifying (through the associated documentation, not by any type enforcement) that only a set of enum values are allowed. Consequently, the resulting code making use of those structures becomes highly error prone, and, particularly in swift, very “old-style” code and difficult to understand for newcomers.

Again, I would like to highlight that my proposal intends to avoid as much as possible the use of enums’ raw values.

Yes, exactly, that’s a great summary of the proposal!

···

El 25 mar 2016, a las 12:25, Haravikk <swift-evolution@haravikk.me> escribió:

On 25 Mar 2016, at 09:56, Carlos Rodríguez Domínguez via swift-evolution <swift-evolution@swift.org> wrote:

The key of this proposal is that the struct/class should come from outside any swift source code, that is, either imported by the compiler from C, or auto-generated from any external tool (i.e., a CoreData autogenerated class from a graphically specified data model). Of course, in well written structures (as specified by Paul Ossenbruggen) we shouldn’t have any need for this proposal. However, many C structures make use of a raw type instead of an enum type, but specifying (through the associated documentation, not by any type enforcement) that only a set of enum values are allowed. Consequently, the resulting code making use of those structures becomes highly error prone, and, particularly in swift, very “old-style” code and difficult to understand for newcomers.

Again, I would like to highlight that my proposal intends to avoid as much as possible the use of enums’ raw values.

I think I may be similarly misunderstanding your proposal; your intention then is to import the type as an enum with raw value (to facilitate the conversion to/from the C code) but without exposing that raw value on the Swift side?

In that case I think I’m in favour.

I think I may be similarly misunderstanding your proposal; your intention then is to import the type as an enum with raw value (to facilitate the conversion to/from the C code) but without exposing that raw value on the Swift side?

In that case I think I’m in favour.

Me too.

But perhaps not through the originally proposed syntax. I don't think this is an extension — it's more of an external annotation on C code, something that we don't currently support for user code. (My understanding is that they have it implemented for Apple frameworks.)

Perhaps, with Swift 3 going Linux, with should expose the ability to annotate external code to the users? And enum importing could be a part of that.

A.

Reposting my comment from that other thread:

[...] it's more of an external annotation on C code, something that we don't currently support for user code. (My understanding is that they have it implemented for Apple frameworks.) Perhaps, with Swift 3 going Linux, with should expose the ability to annotate external code to the users? And enum importing could be a part of that.

A.

As you can observe, that old-style signature is highly error prone, does not comply with swift guidelines, it is difficult to understand, etc. My opinion is that there should be some syntax to rewrite the signature to avoid those issues. For instance, a possible syntax could be:

#mapsignature(socket(_:,_:,_:)->Int32)
func socket(domain:SocketDomain, type:SocketType, protocol:SocketProtocol) -> socket_t? {
  let result = socket(domain.rawValue, type.rawValue, protocol.rawValue)
  if result == -1 {
    return nil
  }
  else{
    return result
  }
}

What's wrong with just overloading it like this without hiding the original? That way you can start by directly porting (perhaps even mechanically converting) the code and later refine it to use the nicer Swift-style overload.

···

--
Brent Royal-Gordon
Architechies

FWIW, there have been a number of proposals in roughly this space, using annotations in the C headers to improve the mapping into Swift, including

  Import as member: https://github.com/apple/swift-evolution/blob/master/proposals/0044-import-as-member.md
  Import Objective-C constants as Swift types: https://github.com/apple/swift-evolution/blob/master/proposals/0033-import-objc-constants.md
  Better translation of Objective-C APIs into Swift (the swift_name attribute part, at least): https://github.com/apple/swift-evolution/blob/master/proposals/0005-objective-c-name-translation.md

  - Doug

···

On Mar 25, 2016, at 3:25 AM, Carlos Rodríguez Domínguez via swift-evolution <swift-evolution@swift.org> wrote:

(Please, take a look at the proposal named "[swift-evolution] Promote "primitive" types to enums in extensions” in order to understand the intention of my proposal as a whole)

This proposal intends to allow developers to rewrite func signatures to better adapt certain imported C functions to swift. For instance, the function to create a POSIX socket has a C signature like this:

int socket(int domain, int type, int protocol);

In swift, it is currently imported like this:

func socket(_: Int32, _: Int32, _: Int32) -> Int32

However, by documentation, the first parameter should be one of a set of constants beginning with PF_. The second one should be either SOCK_STREAM, SOCK_DGRAM or SOCK_RAW. The third one should be a constant specifying the protocol to use. Finally, the result could be either -1 (to indicate an error) or another integer to indicate that a socket descriptor has been returned.

As you can observe, that old-style signature is highly error prone, does not comply with swift guidelines, it is difficult to understand, etc. My opinion is that there should be some syntax to rewrite the signature to avoid those issues. For instance, a possible syntax could be:

#mapsignature(socket(_:,_:,_:)->Int32)
func socket(domain:SocketDomain, type:SocketType, protocol:SocketProtocol) -> socket_t? {
  let result = socket(domain.rawValue, type.rawValue, protocol.rawValue)
  if result == -1 {
    return nil
  }
  else{
    return result
  }
}

Note that the compiler should enforce a function call to the original function that we are rewriting.

After a rewriting has happened, three options may be considered: either to allow the original function to be called, to avoid the original function to be called (through a compiler error with a fix-it) or to emit a warning, advising the developer to adopt the rewritten signature.

Anyhow, this proposal should allow a greatly increased interoperability between old style code and swift, which, in my opinion, is quite “forced” right now.

Well, it might be both an external annotation on C code and something specific within swift. The first is interesting when you have access to the C source code, but the later is good if you either don’t have access to the C source code, or the code (swift, objective-c, C, etc.) is autogenerated by an external tool (for instance, CoreData tools).

···

El 25 mar 2016, a las 14:22, Andrey Tarantsov <andrey@tarantsov.com> escribió:

Reposting my comment from that other thread:

[...] it's more of an external annotation on C code, something that we don't currently support for user code. (My understanding is that they have it implemented for Apple frameworks.) Perhaps, with Swift 3 going Linux, with should expose the ability to annotate external code to the users? And enum importing could be a part of that.

A.

(Recalling from the other thread…)

Well, it might be both an external annotation on C code and something specific within swift. The first is interesting when you have access to the C source code, but the later is good if you either don’t have access to the C source code, or the code (swift, objective-c, C, etc.) is autogenerated by an external tool (for instance, CoreData tools).

···

El 25 mar 2016, a las 14:20, Andrey Tarantsov <andrey@tarantsov.com> escribió:

I think I may be similarly misunderstanding your proposal; your intention then is to import the type as an enum with raw value (to facilitate the conversion to/from the C code) but without exposing that raw value on the Swift side?

In that case I think I’m in favour.

Me too.

But perhaps not through the originally proposed syntax. I don't think this is an extension — it's more of an external annotation on C code, something that we don't currently support for user code. (My understanding is that they have it implemented for Apple frameworks.)

Perhaps, with Swift 3 going Linux, with should expose the ability to annotate external code to the users? And enum importing could be a part of that.

A.

Well, the difference is that the compiler could produce a warning or error with fixit to indicate the developer that an alternative signature to the originally C imported one is available. This way, code ports should gain much readability, while not requiring much effort from the developer to make use of the newer signature.

···

El 26 mar 2016, a las 5:53, Brent Royal-Gordon <brent@architechies.com> escribió:

As you can observe, that old-style signature is highly error prone, does not comply with swift guidelines, it is difficult to understand, etc. My opinion is that there should be some syntax to rewrite the signature to avoid those issues. For instance, a possible syntax could be:

#mapsignature(socket(_:,_:,_:)->Int32)
func socket(domain:SocketDomain, type:SocketType, protocol:SocketProtocol) -> socket_t? {
   let result = socket(domain.rawValue, type.rawValue, protocol.rawValue)
   if result == -1 {
       return nil
   }
   else{
       return result
   }
}

What's wrong with just overloading it like this without hiding the original? That way you can start by directly porting (perhaps even mechanically converting) the code and later refine it to use the nicer Swift-style overload.

--
Brent Royal-Gordon
Architechies

Well, those proposal are more oriented towards annotating on C/Objective-C files to allow a more sophisticate import into swift. However, my proposal is to be able to directly annotate in swift, in order to fix “old-style” imports, autogenerated code, etc. Please, allow me to repeat myself, but consider the example of Core Data, in which model classes are autogenerated from a graphical model that, for instance, lacks from enums’ support. Therefore, if we use Core Data, then we can not use enums (Please, take a look at the proposal named "[swift-evolution] Promote "primitive" types to enums in extensions” in order to understand the intention of my proposal as a whole).

···

El 28 mar 2016, a las 7:29, Douglas Gregor <dgregor@apple.com> escribió:

On Mar 25, 2016, at 3:25 AM, Carlos Rodríguez Domínguez via swift-evolution <swift-evolution@swift.org> wrote:

(Please, take a look at the proposal named "[swift-evolution] Promote "primitive" types to enums in extensions” in order to understand the intention of my proposal as a whole)

This proposal intends to allow developers to rewrite func signatures to better adapt certain imported C functions to swift. For instance, the function to create a POSIX socket has a C signature like this:

int socket(int domain, int type, int protocol);

In swift, it is currently imported like this:

func socket(_: Int32, _: Int32, _: Int32) -> Int32

However, by documentation, the first parameter should be one of a set of constants beginning with PF_. The second one should be either SOCK_STREAM, SOCK_DGRAM or SOCK_RAW. The third one should be a constant specifying the protocol to use. Finally, the result could be either -1 (to indicate an error) or another integer to indicate that a socket descriptor has been returned.

As you can observe, that old-style signature is highly error prone, does not comply with swift guidelines, it is difficult to understand, etc. My opinion is that there should be some syntax to rewrite the signature to avoid those issues. For instance, a possible syntax could be:

#mapsignature(socket(_:,_:,_:)->Int32)
func socket(domain:SocketDomain, type:SocketType, protocol:SocketProtocol) -> socket_t? {
  let result = socket(domain.rawValue, type.rawValue, protocol.rawValue)
  if result == -1 {
    return nil
  }
  else{
    return result
  }
}

Note that the compiler should enforce a function call to the original function that we are rewriting.

After a rewriting has happened, three options may be considered: either to allow the original function to be called, to avoid the original function to be called (through a compiler error with a fix-it) or to emit a warning, advising the developer to adopt the rewritten signature.

Anyhow, this proposal should allow a greatly increased interoperability between old style code and swift, which, in my opinion, is quite “forced” right now.

FWIW, there have been a number of proposals in roughly this space, using annotations in the C headers to improve the mapping into Swift, including

  Import as member: https://github.com/apple/swift-evolution/blob/master/proposals/0044-import-as-member.md
  Import Objective-C constants as Swift types: https://github.com/apple/swift-evolution/blob/master/proposals/0033-import-objc-constants.md
  Better translation of Objective-C APIs into Swift (the swift_name attribute part, at least): https://github.com/apple/swift-evolution/blob/master/proposals/0005-objective-c-name-translation.md

  - Doug

What's wrong with just overloading it like this without hiding the original? That way you can start by directly porting (perhaps even mechanically converting) the code and later refine it to use the nicer Swift-style overload.

Well, the difference is that the compiler could produce a warning or error with fixit to indicate the developer that an alternative signature to the originally C imported one is available. This way, code ports should gain much readability, while not requiring much effort from the developer to make use of the newer signature.

If that's all you want, maybe we can have an attribute which says "prefer this version over that one":

  @preferred(since: 3.0, over: socket(_: Int32, _: Int32, _: Int32) -> Int32)
  func socket(domain:SocketDomain, type:SocketType, protocol:SocketProtocol) -> socket_t? {
    let result = socket(domain.rawValue, type.rawValue, protocol.rawValue)
    if result == -1 {
      return nil
    }
    else{
      return result
    }
  }

This would effectively apply an `@available(deprecated: 3.0, renamed: socket(domain: SocketDomain, type: SocketType, protocol: SocketProtocol) -> socket_t?)` to the other API.

(Or, for that matter, you could simply use an API note to apply that deprecation to the other API, which would not require any new features.)

···

--
Brent Royal-Gordon
Architechies

I’ve been rethinking the proposal and maybe a more suitable syntax should be:

#override(socket(_:,_:,_:)->Int32)
func socket(domain:SocketDomain, type:SocketType, protocol:SocketProtocol) -> socket_t? {
  //…
}

In this way it is clearer that the idea is to bring func overriding to global functions.

Well, those proposal are more oriented towards annotating on C/Objective-C files to allow a more sophisticate import into swift.

Yes, that is true. The philosophy behind these is that it’s better to automatically transform (via annotation) than manually wrap. Naturally, such transformations cannot handle everything.

However, my proposal is to be able to directly annotate in swift, in order to fix “old-style” imports, autogenerated code, etc. Please, allow me to repeat myself, but consider the example of Core Data, in which model classes are autogenerated from a graphical model that, for instance, lacks from enums’ support. Therefore, if we use Core Data, then we can not use enums (Please, take a look at the proposal named "[swift-evolution] Promote "primitive" types to enums in extensions” in order to understand the intention of my proposal as a whole).

There is a Clang attribute “swift_private” that prefixes the name of the declaration with “__” when it is imported into Swift. That way, you can wrap it with a different, more Swift-friendly, API that calls the “__” version.

Note that we do have a mechanism for annotating C/Objective-C APIs without modifying the headers, called “API notes”. It’s a simple YAML format that lets us describe various Clang attributes for entities, e.g., provide the Swift name for a given C function, mark a type as unavailable in Swift, and so on. It’s semi-documented in the swift-clang sources:

  https://github.com/apple/swift-clang/blob/upstream-with-swift/lib/APINotes/APINotesYAMLCompiler.cpp

Essentially, one writes a YAML file for each module that needs annotation. API notes was designed as a transitional technology, so it’s a bit under-designed for a general-purpose tool. However, as we add more Clang-side annotations to improve the mapping of C/Objective-C APIs into Swift, it’s becoming more likely that API notes could/should grow into a more general mechanism for adapting existing C/Objective-C APIs to Swift without manually wrapping everything.

  - Doug

···

On Mar 29, 2016, at 3:02 AM, Carlos Rodríguez Domínguez <carlos@everywaretech.es> wrote:

El 28 mar 2016, a las 7:29, Douglas Gregor <dgregor@apple.com> escribió:

On Mar 25, 2016, at 3:25 AM, Carlos Rodríguez Domínguez via swift-evolution <swift-evolution@swift.org> wrote:

(Please, take a look at the proposal named "[swift-evolution] Promote "primitive" types to enums in extensions” in order to understand the intention of my proposal as a whole)

This proposal intends to allow developers to rewrite func signatures to better adapt certain imported C functions to swift. For instance, the function to create a POSIX socket has a C signature like this:

int socket(int domain, int type, int protocol);

In swift, it is currently imported like this:

func socket(_: Int32, _: Int32, _: Int32) -> Int32

However, by documentation, the first parameter should be one of a set of constants beginning with PF_. The second one should be either SOCK_STREAM, SOCK_DGRAM or SOCK_RAW. The third one should be a constant specifying the protocol to use. Finally, the result could be either -1 (to indicate an error) or another integer to indicate that a socket descriptor has been returned.

As you can observe, that old-style signature is highly error prone, does not comply with swift guidelines, it is difficult to understand, etc. My opinion is that there should be some syntax to rewrite the signature to avoid those issues. For instance, a possible syntax could be:

#mapsignature(socket(_:,_:,_:)->Int32)
func socket(domain:SocketDomain, type:SocketType, protocol:SocketProtocol) -> socket_t? {
  let result = socket(domain.rawValue, type.rawValue, protocol.rawValue)
  if result == -1 {
    return nil
  }
  else{
    return result
  }
}

Note that the compiler should enforce a function call to the original function that we are rewriting.

After a rewriting has happened, three options may be considered: either to allow the original function to be called, to avoid the original function to be called (through a compiler error with a fix-it) or to emit a warning, advising the developer to adopt the rewritten signature.

Anyhow, this proposal should allow a greatly increased interoperability between old style code and swift, which, in my opinion, is quite “forced” right now.

FWIW, there have been a number of proposals in roughly this space, using annotations in the C headers to improve the mapping into Swift, including

  Import as member: https://github.com/apple/swift-evolution/blob/master/proposals/0044-import-as-member.md
  Import Objective-C constants as Swift types: https://github.com/apple/swift-evolution/blob/master/proposals/0033-import-objc-constants.md
  Better translation of Objective-C APIs into Swift (the swift_name attribute part, at least): https://github.com/apple/swift-evolution/blob/master/proposals/0005-objective-c-name-translation.md

  - Doug

If you can’t annotate the headers why not have a wrapper module that uses the C version of the module internally? Then anywhere that uses the original, int using version, has to explicitly import it. (For example a Sqlite module internally imports CSqlite) I don’t know if SwiftPM allows explicit submodules <Modules — Clang 18.0.0git documentation; but if it does that means only your wrapper module has access to the int version.

This seems much better than an annotation that basically only hides an imported function that you’d have to include in any project using the C library anyway.

— Thomas

···

On 29 Mar 2016, at 11:02, Carlos Rodríguez Domínguez via swift-evolution <swift-evolution@swift.org> wrote:

Well, those proposal are more oriented towards annotating on C/Objective-C files to allow a more sophisticate import into swift. However, my proposal is to be able to directly annotate in swift, in order to fix “old-style” imports, autogenerated code, etc. Please, allow me to repeat myself, but consider the example of Core Data, in which model classes are autogenerated from a graphical model that, for instance, lacks from enums’ support. Therefore, if we use Core Data, then we can not use enums (Please, take a look at the proposal named "[swift-evolution] Promote "primitive" types to enums in extensions” in order to understand the intention of my proposal as a whole).