What is wrong with type system?

Good evening, folks.
I recently encountered a need to define a structure to store a function and its related arguments into an instance.

struct Functor<Input, Output> {
    //assuming only fuctions with one argument
    let function: (Input) -> Output
    let inputType: Input.Type
    let outputType: Output.Type
    let input: Input
    let output: Output

    init<Input, Output>(_ function: @escaping (Input) -> Output) {
        self.function = function //there is already a compilation error
        self.input = Input //???? And I have not a clue on how to store argument
    }
}

Compilator says:
error: cannot assign value of type '(Input) -> Output' to type '(Input) -> Output'

The reason I need this is to define custom properties for functions with something like this:

protocol FunctorProtocol: Equatable, Hashable {
    //assiming only functions with one argument
    associatedtype Output
    associatedtype Input

    var function: (Input) -> Output { get set }
    var name: String? { get set }
    var inputType: Input.Type { get set }
    var outputType: Output.Type { get set }
    var preconditions: [(Input) -> Bool] { get set }
    var postconditions: [(Output) -> Bool] { get set }


    func callAsFunction(_ a: Input) throws -> Output
    //func bellow is impossible to implement. Provide a stub
    func isSemanticalyIdentical(to another: Self) -> Bool
    //(...)->(?)
    func hasSignature(identicalTo another: Self) -> Bool
    //(...)
    func hasArgumentSignature(identicalTo another: Self) -> Bool
    func hasSameReturnType(as another: Self) -> Bool


    init<Input, Output>(
        name: String?,
        preconditions: [(Input) -> Bool]?,
        postconditions: [(Input) -> Bool]?,
        inputType: Input,
        outputType: Output,
        function: (Input)->(Output)
    )
}

To then implement bellow:

@CustomStorage(constraints: [{ $0 is Numeric }]) var someNumber: Any = 5 //can store any variable of type Numeric
try? assign(value: 0.5, to: someNumber) //success
try? assign(value: "String", to: someNumber) //failure

Can anybody, please, hint me, if I even doing this correct?

I think you’re shadowing the generic types Input and Output in your initializer. You don’t need to declare new genetic parameter types in it, you should use the ones inherited from the type.

1 Like

Thank you with your responce, I have fixed the code so it is working. But I actualy broke swift in other way :exploding_head: . I am using online swift compiler, to say.
Here is the minimal reproducible example

@Joe_Groff, could you please look

protocol DistilledFunctorProtocol {
    //assiming only functions with one argument
    associatedtype Output
    associatedtype Input

    var function: (Input) -> Output { get }
    var inputType: Input.Type { get }
    var outputType: Output.Type { get }
}
func isSignature<T: DistilledFunctorProtocol, U: DistilledFunctorProtocol>
    (of some: T, identicalTo another: U) -> Bool {
        return some.outputType == another.outputType &&
            some.inputType == another.inputType
}
struct Functor<Input, Output>: DistilledFunctorProtocol {
    //assuming only fuctions with one argument
    let function: (Input) -> Output
    let inputType: Input.Type
    let outputType: Output.Type
    var preconditions: [(Input)->Bool]
    
    init(preconditions: [(Input)->Bool], _ function: @escaping (Input) -> Output) {
        self.function = function
        self.preconditions = preconditions
        self.inputType = Input.self
        self.outputType = Output.self
    }
    enum Unprocessable: Error { case preconditionError,
        postconditionError
    }
    func invoke(with a: Input) throws -> Output {
        for f in preconditions {
            if f(a) == false { throw Unprocessable.preconditionError; break }
            else { return self.function(a) }
        }
    }
}

let a = Functor<Int, Int>.init(preconditions: [{$0 > 10}]) { a in return a + 1 }
let b = Functor<Int, String>.init(preconditions: [{$0 != 0}]) { a in return String(a + 5) }
print(
    isSignature(of: a, identicalTo: b),
    try? a.invoke(with: 11)
)

It is not compiling and even report some wrong stuff happening at lower level.

swift: /home/buildnode/jenkins/workspace/oss-swift-5.1-package-linux-ubuntu-14_04/swift/lib/SILGen/SILGenConvert.cpp:556: virtual swift::SILValue (anonymous namespace)::ExistentialInitialization::getAddressForInPlaceInitialization(swift::Lowering::SILGenFunction &, swift::SILLocation): Assertion `!concreteBuffer && "concrete buffer already formed?!"' failed.
Stack dump:
0.	Program arguments: /swiftplayground/Toolchains/swift-5.1-RELEASE.xctoolchain/usr/bin/swift -frontend -c -primary-file /tmp/B184149F-55C6-4333-91E1-7F0A9BBADE5D.spAatp/main.swift -target x86_64-unknown-linux-gnu -disable-objc-interop -I /swiftplayground/OnlinePlayground/OnlinePlayground-5.1-RELEASE/.build/release -gnone -module-link-name Glibc -suppress-warnings -swift-version 5 -O -module-name SwiftPlayground -o /tmp/main-8f5821.o 
/swiftplayground/Toolchains/swift-5.1-RELEASE.xctoolchain/usr/bin/swift[0x45820b4]
/swiftplayground/Toolchains/swift-5.1-RELEASE.xctoolchain/usr/bin/swift[0x45800b0]
/swiftplayground/Toolchains/swift-5.1-RELEASE.xctoolchain/usr/bin/swift[0x4582418]
/lib/x86_64-linux-gnu/libpthread.so.0(+0x10330)[0x7fd77608c330]
/lib/x86_64-linux-gnu/libc.so.6(gsignal+0x37)[0x7fd77486ec37]
/lib/x86_64-linux-gnu/libc.so.6(abort+0x148)[0x7fd774872028]
/lib/x86_64-linux-gnu/libc.so.6(+0x2fbf6)[0x7fd774867bf6]
/lib/x86_64-linux-gnu/libc.so.6(+0x2fca2)[0x7fd774867ca2]
/swiftplayground/Toolchains/swift-5.1-RELEASE.xctoolchain/usr/bin/swift[0x85cabf]
/swiftplayground/Toolchains/swift-5.1-RELEASE.xctoolchain/usr/bin/swift[0x887f90]
/swiftplayground/Toolchains/swift-5.1-RELEASE.xctoolchain/usr/bin/swift[0x87eaee]
/swiftplayground/Toolchains/swift-5.1-RELEASE.xctoolchain/usr/bin/swift[0x873898]
/swiftplayground/Toolchains/swift-5.1-RELEASE.xctoolchain/usr/bin/swift[0x88c9cf]
/swiftplayground/Toolchains/swift-5.1-RELEASE.xctoolchain/usr/bin/swift[0x85c502]
/swiftplayground/Toolchains/swift-5.1-RELEASE.xctoolchain/usr/bin/swift[0x849016]
/swiftplayground/Toolchains/swift-5.1-RELEASE.xctoolchain/usr/bin/swift[0x858804]
/swiftplayground/Toolchains/swift-5.1-RELEASE.xctoolchain/usr/bin/swift[0x8849d4]
/swiftplayground/Toolchains/swift-5.1-RELEASE.xctoolchain/usr/bin/swift[0x8705f2]
/swiftplayground/Toolchains/swift-5.1-RELEASE.xctoolchain/usr/bin/swift[0x8dfd90]
/swiftplayground/Toolchains/swift-5.1-RELEASE.xctoolchain/usr/bin/swift[0x8e0601]
/swiftplayground/Toolchains/swift-5.1-RELEASE.xctoolchain/usr/bin/swift[0x90b203]
/swiftplayground/Toolchains/swift-5.1-RELEASE.xctoolchain/usr/bin/swift[0x90bf6e]
/swiftplayground/Toolchains/swift-5.1-RELEASE.xctoolchain/usr/bin/swift[0x90a355]
/swiftplayground/Toolchains/swift-5.1-RELEASE.xctoolchain/usr/bin/swift[0x908b9c]
/swiftplayground/Toolchains/swift-5.1-RELEASE.xctoolchain/usr/bin/swift[0x907260]
/swiftplayground/Toolchains/swift-5.1-RELEASE.xctoolchain/usr/bin/swift[0x906818]
/swiftplayground/Toolchains/swift-5.1-RELEASE.xctoolchain/usr/bin/swift[0x8f66ce]
/swiftplayground/Toolchains/swift-5.1-RELEASE.xctoolchain/usr/bin/swift[0x8f55b8]
/swiftplayground/Toolchains/swift-5.1-RELEASE.xctoolchain/usr/bin/swift[0x87e702]
/swiftplayground/Toolchains/swift-5.1-RELEASE.xctoolchain/usr/bin/swift[0x873db1]
/swiftplayground/Toolchains/swift-5.1-RELEASE.xctoolchain/usr/bin/swift[0x836389]
/swiftplayground/Toolchains/swift-5.1-RELEASE.xctoolchain/usr/bin/swift[0x836cbc]
/swiftplayground/Toolchains/swift-5.1-RELEASE.xctoolchain/usr/bin/swift[0x837eab]
/swiftplayground/Toolchains/swift-5.1-RELEASE.xctoolchain/usr/bin/swift[0x83830a]
/swiftplayground/Toolchains/swift-5.1-RELEASE.xctoolchain/usr/bin/swift[0x501544]
/swiftplayground/Toolchains/swift-5.1-RELEASE.xctoolchain/usr/bin/swift[0x4fe77c]
/swiftplayground/Toolchains/swift-5.1-RELEASE.xctoolchain/usr/bin/swift[0x4a2af2]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf5)[0x7fd774859f45]
/swiftplayground/Toolchains/swift-5.1-RELEASE.xctoolchain/usr/bin/swift[0x4a2708]
<unknown>:0: error: unable to execute command: Aborted
<unknown>:0: error: compile command failed due to signal 6 (use -v to see invocation)

Do you know what might be wrong?

There are two issues:
one is that print needs a simpler type in the invoke line

print(
    isSignature(of: a, identicalTo: b),
    (try? a.invoke(with: 11)) ?? 0 
)

and the other is in the implementation of invoke; in case the array of preconditions is empty, this implementation has no return statement: you can fix it by tacking an extra return statement at the bottom of the function.

func invoke(with a: Input) throws -> Output {
        for f in preconditions {
            if f(a) == false { throw Unprocessable.preconditionError; break }
            else { return self.function(a) }
        }

        return self.function(a)
    }

About the isSignature function: why do you need a runtime check? You can turn it into a compile-time error using a where clause. At this point you don't even need this function anymore, as you can constraint the types of the rest of your logic.

func isSignature<
    T: DistilledFunctorProtocol,
    U: DistilledFunctorProtocol
>(
    of some: T,
    identicalTo another: U
) where T.Input == U.Input, T.Output == U.Output
{}

About the compiler error: I copy pasted your code in a Xcode 11.2.1 playground and I didn't get the compiler crash you got. :thinking:

Ok, got it. It is possible to specialize some cases of isSignature with where. But because some Functor types are generic and may be created at runtime, it is necessary to use more generalized solution, I think

Terms of Service

Privacy Policy

Cookie Policy