পাইথন ইন্টারঅপারেবিলিটি

পাইথন এপিআই ইন্টারঅপারেবিলিটি এই প্রকল্পের জন্য একটি গুরুত্বপূর্ণ প্রয়োজন। যদিও সুইফটকে অন্যান্য প্রোগ্রামিং ভাষার (এবং তাদের রানটাইম) সাথে একীভূত করার জন্য ডিজাইন করা হয়েছে, তবে গতিশীল ভাষার প্রকৃতির জন্য স্ট্যাটিক ভাষা সমর্থন করার জন্য প্রয়োজনীয় গভীর একীকরণের প্রয়োজন হয় না। বিশেষ করে পাইথনকে অন্য অ্যাপ্লিকেশনে এম্বেড করার জন্য ডিজাইন করা হয়েছে এবং এর একটি সাধারণ C ইন্টারফেস API রয়েছে। আমাদের কাজের উদ্দেশ্যে, আমরা একটি মেটা-এম্বেডিং প্রদান করতে পারি, যা সুইফ্ট প্রোগ্রামগুলিকে পাইথন API ব্যবহার করতে দেয় যেন তারা সরাসরি পাইথনকে এম্বেড করছে।

এটি সম্পন্ন করার জন্য, সুইফ্ট স্ক্রিপ্ট/প্রোগ্রাম কেবল পাইথন ইন্টারপ্রেটারকে তার কোডের সাথে লিঙ্ক করে। আমাদের লক্ষ্য "আমরা পাইথন এপিআইগুলির সাথে কীভাবে কাজ করি" থেকে একটি প্রশ্নে পরিবর্তিত হয় "কীভাবে আমরা পাইথন এপিআইগুলিকে প্রাকৃতিক, অ্যাক্সেসযোগ্য এবং সুইফ্ট কোড থেকে পৌঁছানো সহজ মনে করি?" এটি একটি তুচ্ছ সমস্যা নয় - সুইফ্ট এবং পাইথনের মধ্যে ডিজাইনের উল্লেখযোগ্য পার্থক্য রয়েছে, যার মধ্যে রয়েছে ত্রুটি পরিচালনার পদ্ধতি, পাইথনের সুপার-ডাইনামিক প্রকৃতি, দুটি ভাষার মধ্যে পৃষ্ঠ-স্তরের সিনট্যাক্সের পার্থক্য এবং না করার ইচ্ছা। সুইফ্ট প্রোগ্রামাররা যে জিনিসগুলি আশা করে সেগুলিকে "সমঝোতা" করুন৷ আমরা সুবিধা এবং এরগনোমিক্সের বিষয়েও যত্নশীল এবং মনে করি যে SWIG-এর মতো একটি মোড়ক জেনারেটরের প্রয়োজন অগ্রহণযোগ্য।

সামগ্রিক পদ্ধতি

আমাদের সামগ্রিক পদ্ধতির পর্যবেক্ষণের উপর ভিত্তি করে যে পাইথন দৃঢ়ভাবে টাইপ করা হয়েছে কিন্তু - বেশিরভাগ গতিশীলভাবে টাইপ করা ভাষার মতো - এর টাইপ সিস্টেম রানটাইমে প্রয়োগ করা হয়। যদিও এটির উপরে একটি স্ট্যাটিক টাইপ সিস্টেমকে পুনরুদ্ধার করার অনেক প্রচেষ্টা করা হয়েছে (যেমন mypy , pytype এবং অন্যান্য ), তারা অসাউন্ড টাইপ সিস্টেমের উপর নির্ভর করে যাতে তারা একটি সম্পূর্ণ সমাধান নয় যার উপর আমরা নির্ভর করতে পারি, এবং উপরন্তু তারা অনেকের বিরুদ্ধে কাটাতে পারে। পাইথন এবং এর লাইব্রেরিগুলিকে সত্যিই দুর্দান্ত করে তোলে এমন ডিজাইন প্রাঙ্গনে।

অনেক লোক সুইফটকে একটি স্ট্যাটিক্যালি টাইপ করা ভাষা হিসেবে দেখে এবং তাই তারা এই সিদ্ধান্তে ঝাঁপিয়ে পড়ে যে সঠিক সমাধান হল পাইথনের তরল ফর্মটিকে একটি স্থিরভাবে সংজ্ঞায়িত গর্তে ফেলা। যাইহোক, অন্যরা বুঝতে পারে যে সুইফট একটি শক্তিশালী স্ট্যাটিক টাইপ সিস্টেমের সুবিধাগুলিকে একটি (প্রায়শই কম-প্রশংসিত!) গতিশীল টাইপ সিস্টেমের সাথে একত্রিত করে। পাইথনের ডায়নামিক টাইপ সিস্টেমকে এমন কিছু হতে বাধ্য করার চেষ্টা করার পরিবর্তে, আমরা পাইথনের সাথে দেখা করতে বেছে নিই যেখানে এটি আছে এবং সম্পূর্ণরূপে এর গতিশীলভাবে টাইপ করা পদ্ধতিকে আলিঙ্গন করি।

এর শেষ ফলাফল হল আমরা একটি খুব স্বাভাবিক পাইথন অভিজ্ঞতা অর্জন করতে পারি - সরাসরি সুইফট কোডে। এখানে এই মত দেখায় একটি উদাহরণ; মন্তব্য করা কোড তুলনার জন্য বিশুদ্ধ-পাইথন সিনট্যাক্স দেখায়:

import PythonKit

// Python:
//    import numpy as np
//    a = np.arange(15).reshape(3, 5)
//    b = np.array([6, 7, 8])
let np = Python.import("numpy")
let a = np.arange(15).reshape(3, 5)
let b = np.array([6, 7, 8])

// Python:
//    import gzip as gzip
//    import pickle as pickle
let gzip = Python.import("gzip")
let pickle = Python.import("pickle")

// Python:
//    file = gzip.open("mnist.pkl.gz", "rb")
//    (images, labels) = pickle.load(file)
//    print(images.shape)  # (50000, 784)
let file = gzip.open("mnist.pkl.gz", "rb")
let (images, labels) = pickle.load(file).tuple2
print(images.shape) // (50000, 784)

আপনি দেখতে পাচ্ছেন, এখানে সিনট্যাক্সটি পাইথন প্রোগ্রামারের কাছে অবিলম্বে বোধগম্য: প্রধান পার্থক্য হল যে সুইফট ব্যবহারের আগে মানগুলি ঘোষণা করতে হবে ( let বা var সহ) এবং আমরা পাইথন বিল্টইন ফাংশন যেমন import , type , slice রাখতে বেছে নিয়েছি একটি Python. নামস্থান (কেবলমাত্র বিশ্বব্যাপী সুযোগের বিশৃঙ্খলা এড়াতে)। এটি পাইথনকে প্রাকৃতিক এবং পরিচিত বোধ করার চেষ্টা করার মধ্যে একটি সচেতন ভারসাম্যের ফলাফল, যখন সুইফ্ট ভাষার বৈশ্বিক নকশার সাথে আপস না করে।

এই লাইনটি একটি সাধারণ প্রয়োজনের মাধ্যমে প্রতিষ্ঠিত হয়েছে: পাইথন ইন্টারপ অর্জনের জন্য আমাদের কোনো পাইথন-নির্দিষ্ট কম্পাইলার বা ভাষার বৈশিষ্ট্যের উপর নির্ভর করা উচিত নয় - এটি একটি সুইফট লাইব্রেরি হিসাবে সম্পূর্ণরূপে প্রয়োগ করা উচিত। সর্বোপরি, যদিও পাইথন মেশিন লার্নিং সম্প্রদায়ের জন্য অবিশ্বাস্যভাবে গুরুত্বপূর্ণ, সেখানে অন্যান্য গতিশীল ভাষা (জাভাস্ক্রিপ্ট, রুবি, ইত্যাদি) রয়েছে যেগুলির অন্যান্য ডোমেনে শক্তিশালী অবস্থান রয়েছে এবং আমরা চাই না যে এই ডোমেনগুলির প্রত্যেকটি একটি অন্তহীন জটিলতা আরোপ করুক। সুইফট ভাষার দিকে।

আপনি Python.swift- এ আমাদের ব্রিজিং লেয়ারের বর্তমান বাস্তবায়ন দেখতে পারেন। এটি বিশুদ্ধ সুইফট কোড যা অপরিবর্তিত সুইফটের সাথে কাজ করে।

এই পদ্ধতির সীমাবদ্ধতা

যেহেতু আমরা সুইফ্টে পাইথনের গতিশীল প্রকৃতিকে আলিঙ্গন করতে বেছে নিই, তাই গতিশীল ভাষাগুলি তাদের সাথে নিয়ে আসা ভালো এবং অসুবিধা উভয়ই আমরা পাই। বিশেষত, অনেক সুইফ্ট প্রোগ্রামাররা আশা করতে এসেছেন এবং আশ্চর্যজনক কোড সমাপ্তির উপর নির্ভর করেছেন এবং কম্পাইলের সময় তাদের জন্য কম্পাইলার ক্যাচ টাইপো এবং অন্যান্য তুচ্ছ বাগ থাকার স্বাচ্ছন্দ্যের প্রশংসা করেছেন। বিপরীতে, পাইথন প্রোগ্রামারদের এই সামর্থ্য নেই (এর পরিবর্তে, বাগগুলি সাধারণত রানটাইমে ধরা পড়ে) এবং যেহেতু আমরা পাইথনের গতিশীল প্রকৃতিকে আলিঙ্গন করছি, তাই সুইফটের পাইথন এপিআই একইভাবে কাজ করে।

সুইফ্ট সম্প্রদায়ের সাথে সতর্কতার সাথে বিবেচনা করার পরে, এটি পরিষ্কার হয়ে গেছে যে এটি একটি ভারসাম্য: পাইথন লাইব্রেরি ইকোসিস্টেমে সুইফটের কতটা দর্শন এবং মূল্যবোধ প্রজেক্ট করা যেতে পারে... পাইথন সম্পর্কে সত্য এবং সুন্দর জিনিসগুলিকে ভেঙে না দিয়ে এবং এর লাইব্রেরি? শেষ পর্যন্ত, আমরা উপসংহারে পৌঁছেছি যে একটি পাইথন-কেন্দ্রিক মডেল হল সর্বোত্তম আপস: আমাদের এই সত্যটি গ্রহণ করা উচিত যে পাইথন একটি গতিশীল ভাষা, এটি স্ট্যাটিক কম্পাইল সময়ে নিখুঁত কোড সমাপ্তি এবং ত্রুটি সনাক্তকরণ কখনই করতে পারে না এবং হতে পারে না।

কিভাবে এটা কাজ করে

আমরা পাইথনের ডায়নামিক টাইপ সিস্টেমকে PythonObject নামে একটি একক স্ট্যাটিক সুইফ্ট টাইপে ম্যাপ করি এবং PythonObject রানটাইমে যেকোনো গতিশীল পাইথন মান গ্রহণ করার অনুমতি দিই ( Abadi et al. এর পদ্ধতির অনুরূপ)। PythonObject সরাসরি পাইথন সি বাইন্ডিং-এ ব্যবহৃত PyObject* এর সাথে মিলে যায় এবং Python-এ Python মান যা করে তা করতে পারে। উদাহরণস্বরূপ, আপনি পাইথনে যেমন আশা করেন ঠিক তেমনই এটি কাজ করে:

var x: PythonObject = 42  // x is an integer represented as a Python value.
print(x + 4)         // Does a Python addition, then prints 46.

x = "stringy now"    // Python values can hold strings, and dynamically change Python type!
print("super " + x)  // Does a Python addition, then prints "super stringy now".

যেহেতু আমরা সুইফটের গ্লোবাল ডিজাইনে আপস করতে চাই না, তাই আমরা পাইথনের সমস্ত আচরণকে এই PythonObject টাইপের অভিব্যক্তিতে সীমাবদ্ধ রাখি। এটি নিশ্চিত করে যে সাধারণ সুইফ্ট কোডের শব্দার্থবিদ্যা অপরিবর্তিত থাকে, এমনকি যদি এটি পাইথন মানগুলির সাথে মিশ্রিত, ম্যাচিং, ইন্টারফেসিং এবং মিশ্রিত হয়।

বেসিক ইন্টারঅপারেবিলিটি

সুইফ্ট 4.0-এর হিসাবে, বিদ্যমান ভাষার বৈশিষ্ট্যগুলির মাধ্যমে মৌলিক আন্তঃকার্যক্ষমতার একটি যুক্তিসঙ্গত স্তর ইতিমধ্যেই সরাসরি অর্জনযোগ্য ছিল: আমরা কেবল PythonObject একটি সুইফ্ট কাঠামো হিসাবে সংজ্ঞায়িত করি যা একটি ব্যক্তিগত সুইফ্ট PyReference শ্রেণীকে মোড়ানো, সুইফটকে পাইথন রেফারেন্স গণনার দায়িত্ব নিতে দেয়:

/// Primitive reference to a Python value.  This is always non-null and always
/// owning of the underlying value.
private final class PyReference {
  var state: UnsafeMutablePointer<PyObject>

  init(owned: UnsafeMutablePointer<PyObject>) {
    state = owned
  }

  init(borrowed: UnsafeMutablePointer<PyObject>) {
    state = borrowed
    Py_IncRef(state)
  }

  deinit {
    Py_DecRef(state)
  }
}

// This is the main type users work with.
public struct PythonObject {
  /// This is a handle to the Python object the PythonObject represents.
  fileprivate var state: PyReference
  ...
}

একইভাবে, আমরা বিদ্যমান পাইথন রানটাইম ইন্টারফেসের পরিপ্রেক্ষিতে PythonObjectfunc + (এবং সমর্থিত পাইথন অপারেটরগুলি) প্রয়োগ করতে পারি। আমাদের বাস্তবায়ন এই মত দেখায়:

// Implement the + operator in terms of the standard Python __add__ method.
public static func + (lhs: PythonObject, rhs: PythonObject) -> PythonObject {
  return lhs.__add__.call(with: rhs)
}
// Implement the - operator in terms of the standard Python __sub__ method.
public static func - (lhs: PythonObject, rhs: PythonObject) -> PythonObject {
  return lhs.__sub__.call(with: rhs)
}
// Implement += and -= in terms of + and -, as usual.
public static func += (lhs: inout PythonObject, rhs: PythonObject) {
  lhs = lhs + rhs
}
public static func -= (lhs: inout PythonObject, rhs: PythonObject) {
  lhs = lhs - rhs
}
// etc...

আমরা PythonObject Sequence এবং অন্যান্য প্রোটোকলের সাথে সঙ্গতিপূর্ণ করি, এই ধরনের কোডকে কাজ করার অনুমতি দেয়:

func printPythonCollection(_ collection: PythonObject) {
  for elt in collection {
    print(elt)
  }
}

উপরন্তু, যেহেতু PythonObject MutableCollection এর সাথে সামঞ্জস্যপূর্ণ, তাই আপনি সংগ্রহের জন্য সুইফট API- এ সম্পূর্ণ অ্যাক্সেস পাবেন, যার মধ্যে map , filter , sort মতো ফাংশন রয়েছে।

সুইফ্ট মান এবং থেকে রূপান্তর

এখন যেহেতু সুইফ্ট পাইথন মানগুলিকে উপস্থাপন করতে এবং পরিচালনা করতে পারে, তাই সুইফট নেটিভ প্রকার যেমন Int এবং Array<Float> এবং Python সমতুল্যগুলির মধ্যে রূপান্তর করতে সক্ষম হওয়া গুরুত্বপূর্ণ হয়ে ওঠে। এটি PythonConvertible প্রোটোকল দ্বারা পরিচালিত হয় - যার সাথে Int এর মতো মৌলিক সুইফট প্রকারগুলি মেনে চলে এবং Array এবং Dictionary এর মতো সুইফ্ট সংগ্রহের প্রকারগুলি শর্তসাপেক্ষে (যখন তাদের উপাদানগুলি মেনে চলে)। এটি রূপান্তরগুলিকে সুইফ্ট মডেলে স্বাভাবিকভাবে ফিট করে তোলে।

উদাহরণস্বরূপ, যদি আপনি জানেন যে আপনার একটি সুইফ্ট পূর্ণসংখ্যা প্রয়োজন বা আপনি একটি সুইফট পূর্ণসংখ্যাকে পাইথনে রূপান্তর করতে চান, আপনি ব্যবহার করতে পারেন:

let pyInt = PythonObject(someSwiftInteger)     // Always succeeds.
if let swiftInt = Int(somePythonValue) {  // Succeeds if the Python value is convertible to Int.
  print(swiftInt)
}

একইভাবে, অ্যারের মতো সামগ্রিক প্রকারগুলি ঠিক একইভাবে কাজ করে:

// This succeeds when somePythonValue is a collection of values that are convertible to Int.
if let swiftIntArray = Array<Int>(somePythonValue) {
  print(swiftIntArray)
}

এটি একটি সুইফট প্রোগ্রামার আশা করা মডেলের সাথে ঠিক খাপ খায়: ব্যর্থ রূপান্তরগুলি ঐচ্ছিক ফলাফলে অনুমান করা হয় (যেমন "স্ট্রিং থেকে int" রূপান্তরগুলি হয়), সুইফট প্রোগ্রামাররা যে নিরাপত্তা এবং পূর্বাভাস দেয় তা প্রদান করে।

অবশেষে, যেহেতু আপনার কাছে পাইথনের সম্পূর্ণ শক্তির অ্যাক্সেস রয়েছে, তাই পাইথনের সমস্ত স্বাভাবিক প্রতিফলিত ক্ষমতা সরাসরি পাওয়া যায়, যার মধ্যে রয়েছে Python.type , Python.id , Python.dir , এবং Python inspect মডিউল।

ইন্টারঅপারেবিলিটি চ্যালেঞ্জ

উপরের সমর্থনটি সম্ভব কারণ সুইফ্টের ডিজাইনটি লাইব্রেরি-স্তরের সিনট্যাকটিক এক্সটেনসিবিলিটির ধরণের লক্ষ্যের জন্য লক্ষ্য করে এবং প্রশংসা করে। আমরা সৌভাগ্যবান যে পাইথন এবং সুইফ্ট এক্সপ্রেশনের (অপারেটর এবং ফাংশন/পদ্ধতি কল) জন্য খুব অনুরূপ পৃষ্ঠ-স্তরের সিনট্যাক্স ভাগ করে নেয়। তাতে বলা হয়েছে, সুইফট 4.0 এর সিনট্যাক্স এক্সটেনসিবিলিটি এবং ইচ্ছাকৃত ডিজাইনের পার্থক্যের সীমাবদ্ধতার কারণে আমরা কয়েকটি চ্যালেঞ্জের মুখোমুখি হয়েছি যা আমাদের অতিক্রম করতে হবে।

ডায়নামিক সদস্য সন্ধান

যদিও সুইফ্ট একটি সাধারণভাবে সম্প্রসারণযোগ্য ভাষা, আদিম সদস্য লুকআপ একটি লাইব্রেরি-সম্প্রসারণযোগ্য বৈশিষ্ট্য ছিল না। বিশেষভাবে, xy ফর্মের একটি অভিব্যক্তি দেওয়া হলে, x এর ধরনটি নিয়ন্ত্রণ করতে অক্ষম ছিল যখন একজন সদস্য y এটিতে অ্যাক্সেস করা হয়েছিল তখন কী ঘটেছিল। যদি x এর ধরনটি স্থিরভাবে y নামের একটি সদস্যকে ঘোষণা করে থাকে তবে এই অভিব্যক্তিটি সমাধান করা হবে, অন্যথায় এটি কম্পাইলার দ্বারা প্রত্যাখ্যান করা হবে।

সুইফটের সীমাবদ্ধতার মধ্যে, আমরা একটি বাঁধাই তৈরি করেছি যা এটিকে ঘিরে কাজ করেছিল। উদাহরণস্বরূপ, পাইথনের PyObject_GetAttrString এবং PyObject_SetAttrString এর পরিপ্রেক্ষিতে সদস্য অ্যাক্সেসগুলি বাস্তবায়ন করা সহজ ছিল। এই অনুমোদিত কোড যেমন:

// Python: a.x = a.x + 1
a.set(member: "x", to: a.get(member: "x") + 1)

যাইহোক, আমরা সম্ভবত সবাই একমত হতে পারি যে এটি পাইথন মানগুলির সাথে কাজ করার জন্য একটি প্রাকৃতিক এবং এরগনোমিক ইন্টারফেস প্রদানের আমাদের লক্ষ্য অর্জন করে না! এর বাইরে, এটি সুইফট এল-ভ্যালুসের সাথে কাজ করার জন্য কোনো সামর্থ্য প্রদান করে না: ax += 1 এর সমতুল্য বানান করার কোনো উপায় নেই। একসাথে এই দুটি সমস্যা একটি উল্লেখযোগ্য অভিব্যক্তির ফাঁক ছিল।

সুইফ্ট সম্প্রদায়ের সাথে আলোচনার পরে, এই সমস্যার সমাধান হল লাইব্রেরি কোডকে ব্যর্থ সদস্য লুকআপগুলি পরিচালনা করার জন্য একটি ফলব্যাক হুক প্রয়োগ করার অনুমতি দেওয়া। এই বৈশিষ্ট্যটি অবজেক্টিভ-সি সহ অনেক গতিশীল ভাষাতে বিদ্যমান, এবং যেমন, আমরা SE-0195 প্রস্তাবিত এবং প্রয়োগ করেছি: ব্যবহারকারী-সংজ্ঞায়িত "ডাইনামিক মেম্বার লুকআপ" প্রকারগুলি প্রবর্তন করুন যা একটি স্ট্যাটিক টাইপকে অমীমাংসিত লুকআপগুলির জন্য একটি ফলব্যাক হ্যান্ডলার প্রদান করতে দেয়৷ এই প্রস্তাবটি সুইফ্ট বিবর্তন প্রক্রিয়ার মাধ্যমে সুইফট সম্প্রদায়ের দ্বারা দীর্ঘ আলোচনা করা হয়েছিল এবং শেষ পর্যন্ত গৃহীত হয়েছিল। এটি সুইফট 4.1 থেকে শিপিং করা হয়েছে।

এর ফলস্বরূপ, আমাদের আন্তঃঅপারেবিলিটি লাইব্রেরি নিম্নলিখিত হুক বাস্তবায়ন করতে সক্ষম:

@dynamicMemberLookup
public struct PythonObject {
...
  subscript(dynamicMember member: String) -> PythonObject {
    get {
      return ... PyObject_GetAttrString(...) ...
    }
    set {
      ... PyObject_SetAttrString(...)
    }
  }
}

যা উপরের কোডটিকে সহজভাবে প্রকাশ করার অনুমতি দেয়:

// Python: a.x = a.x + 1
a.x = a.x + 1

... এবং প্রাকৃতিক ax += 1 সিনট্যাক্স ঠিক আমাদের প্রত্যাশা মত কাজ করে. এটি একটি লক্ষ্য অর্জনের জন্য একটি ভাষা, এর লাইব্রেরি এবং অ্যাপ্লিকেশনগুলির সম্পূর্ণ স্ট্যাক বিকশিত করতে সক্ষম হওয়ার বিশাল সুবিধা দেখায়।

গতিশীলভাবে কলযোগ্য প্রকার

সদস্যের সন্ধানের পাশাপাশি, কলিং মানগুলির ক্ষেত্রে আমাদের কাছে একই রকম চ্যালেঞ্জ রয়েছে। গতিশীল ভাষাগুলিতে প্রায়ই "কলযোগ্য" মানগুলির ধারণা থাকে, যা একটি নির্বিচারে স্বাক্ষর নিতে পারে, তবে সুইফট 4.1-এর এই জাতীয় জিনিসের জন্য কোনও সমর্থন নেই। উদাহরণস্বরূপ, সুইফ্ট 4.1 হিসাবে, আমাদের আন্তঃঅপারেবিলিটি লাইব্রেরি পাইথন এপিআইগুলির সাথে এইরকম একটি ইন্টারফেসের মাধ্যমে কাজ করতে সক্ষম:

// Python: a = np.arange(15).reshape(3, 5)
let a = np.arange.call(with: 15).reshape.call(with: 3, 5)

// Python: d = np.array([1, 2, 3], dtype="i2")
let d = np.array.call(with: [6, 7, 8], kwargs: [("dtype", "i2")])

যদিও এটি দিয়ে জিনিসগুলি করা সম্ভব, এটি স্পষ্টতই আমাদের সুবিধার এবং এরগনোমিক্সের লক্ষ্য অর্জন করছে না।

সুইফ্ট সম্প্রদায় এবং #2 এর সাথে এই সমস্যাটি মূল্যায়ন করে, আমরা লক্ষ্য করি যে পাইথন এবং সুইফট নামযুক্ত এবং নামবিহীন উভয় আর্গুমেন্ট সমর্থন করে: নামযুক্ত আর্গুমেন্টগুলি একটি অভিধান হিসাবে পাস করা হয়। একই সময়ে, Smalltalk- থেকে প্রাপ্ত ভাষাগুলি একটি অতিরিক্ত বলি যোগ করে: পদ্ধতির রেফারেন্সগুলি হল পারমাণবিক একক, যা যেকোন কীওয়ার্ড আর্গুমেন্টের সাথে পদ্ধতির মূল নাম অন্তর্ভুক্ত করে। যদিও এই শৈলীর ভাষার সাথে আন্তঃঅপারেবিলিটি পাইথনের জন্য গুরুত্বপূর্ণ নয়, আমরা নিশ্চিত করতে চাই যে সুইফট এমন কোন কোণে আঁকা না যা রুবি, স্কুইক এবং অন্যান্য SmallTalk- থেকে প্রাপ্ত ভাষার সাথে দুর্দান্ত ইন্টারপকে বাধা দেয়।

আমাদের সমাধান, যা Swift 5 এ প্রয়োগ করা হয়েছিল , তা হল একটি নতুন @dynamicCallable বৈশিষ্ট্য প্রবর্তন করা যাতে নির্দেশ করা যায় যে একটি প্রকার (যেমন PythonObject ) গতিশীল কল রেজোলিউশন পরিচালনা করতে পারে। @dynamicCallable বৈশিষ্ট্যটি বাস্তবায়ন করা হয়েছে এবং পাইথনকিট ইন্টারপ মডিউলে উপলব্ধ করা হয়েছে।

// Python: a = np.arange(15).reshape(3, 5)
let a = np.arange(15).reshape(3, 5)

// Python: d = np.array([1, 2, 3], dtype="i2")
let d = np.array([6, 7, 8], dtype: "i2")

আমরা মনে করি যে এটি বেশ বাধ্যতামূলক, এবং এই ক্ষেত্রে বিদ্যমান অবশিষ্ট অভিব্যক্তি এবং ergonomic ফাঁক বন্ধ করে দেয়। আমরা বিশ্বাস করি যে এই বৈশিষ্ট্যটি রুবি, স্কুইক এবং অন্যান্য গতিশীল ভাষার জন্য একটি ভাল সমাধান হবে, সেইসাথে একটি সাধারণভাবে দরকারী সুইফট ভাষার বৈশিষ্ট্য যা অন্যান্য সুইফ্ট লাইব্রেরিতে প্রযোজ্য হতে পারে।

ব্যতিক্রম হ্যান্ডলিং বনাম ত্রুটি পরিচালনা

ব্যতিক্রম পরিচালনার ক্ষেত্রে পাইথনের দৃষ্টিভঙ্গি C++ এবং অন্যান্য অনেক ভাষার মতোই, যেখানে যেকোনো অভিব্যক্তি যে কোনো সময়ে একটি ব্যতিক্রম ছুঁড়ে দিতে পারে এবং কলকারীরা স্বাধীনভাবে সেগুলি পরিচালনা করতে (বা না) বেছে নিতে পারে। বিপরীতে, সুইফটের ত্রুটি হ্যান্ডলিং পদ্ধতি "থ্রোওবিলিটি" কে একটি পদ্ধতির API চুক্তির একটি সুস্পষ্ট অংশ করে তোলে এবং কলকারীদের হ্যান্ডেল করতে বাধ্য করে (বা অন্তত স্বীকার করে) যে একটি ত্রুটি নিক্ষেপ করা যেতে পারে।

এটি দুটি ভাষার মধ্যে একটি অন্তর্নিহিত ব্যবধান, এবং আমরা একটি ভাষা এক্সটেনশনের সাথে এই পার্থক্যটি কাগজপত্র করতে চাই না। আমাদের বর্তমান সমাধানটি এই পর্যবেক্ষণের উপর ভিত্তি করে তৈরি করে যে যদিও যে কোনও ফাংশন কল থ্রো করতে পারে , বেশিরভাগ কলই তা করে না। তদ্ব্যতীত, সুইফ্ট ভাষায় স্পষ্টভাবে ত্রুটি পরিচালনা করে, এটি একটি পাইথন-ইন-সুইফ্ট প্রোগ্রামারের পক্ষে চিন্তা করা যুক্তিসঙ্গত যে তারা কোথায় ত্রুটিগুলি নিক্ষেপযোগ্য এবং ধরার যোগ্য হবে বলে আশা করে। আমরা PythonObject এ একটি স্পষ্ট .throwing প্রজেকশন দিয়ে এটি করি। এখানে একটি উদাহরণ:

  // Open a file.  If this fails, the program is terminated, just like an
  // unhandled exception in Python.

  // file = open("foo.txt")
  let file = Python.open("foo.txt")
  // blob = file.read()
  let blob = file.read()

  // Open a file, a thrown "file not found" exception is turned into a Swift error.
  do {
    let file = try Python.open.throwing.dynamicallyCall("foo.txt")
    let blob = file.read()
    ...
  } catch {
    print(error)
  }

এবং অবশ্যই, এটি সুইফ্ট ত্রুটি হ্যান্ডলিং দ্বারা প্রদত্ত সমস্ত স্বাভাবিক মেকানিক্সের সাথে সংহত করে, try? আপনি যদি ত্রুটিটি পরিচালনা করতে চান তবে ব্যতিক্রমের মধ্যে অন্তর্ভুক্ত বিশদ সম্পর্কে চিন্তা করবেন না।

বর্তমান বাস্তবায়ন এবং অবস্থা

উপরে উল্লিখিত হিসাবে, পাইথন ইন্টারঅপারেবিলিটি লাইব্রেরির আমাদের বর্তমান বাস্তবায়ন Python.swift ফাইলে GitHub-এ উপলব্ধ। অনুশীলনে, আমরা দেখেছি যে এটি অনেক ব্যবহারের ক্ষেত্রে সুন্দরভাবে কাজ করে। যাইহোক, কিছু জিনিস অনুপস্থিত যা আমাদের বিকাশ চালিয়ে যেতে এবং বের করতে হবে:

পাইথন স্লাইসিং সুইফটের স্লাইসিং সিনট্যাক্সের চেয়ে বেশি সাধারণ। এই মুহূর্তে আপনি Python.slice(a, b, c) ফাংশনের মাধ্যমে এটিতে সম্পূর্ণ অ্যাক্সেস পেতে পারেন। যাইহোক, আমাদের সুইফট থেকে সাধারন a...b রেঞ্জ সিনট্যাক্সে ওয়্যার করা উচিত, এবং সেই বেসিক রেঞ্জ সিনট্যাক্সের এক্সটেনশন হিসাবে স্ট্রাইডিং অপারেটরগুলি বাস্তবায়ন করা বিবেচনা করা আকর্ষণীয় হতে পারে। পাইথন ক্লাসের সাবক্লাসিংয়ের জন্য ব্যবহার করার জন্য আমাদের সঠিক মডেলটি তদন্ত এবং স্থির করতে হবে। বর্তমানে PythonObject মতো একটি স্ট্রাকট তৈরি করার কোনো উপায় নেই যা tuple প্যাটার্ন ম্যাচিং দিয়ে কাজ করে, তাই আমরা .tuple2 এর মতো প্রজেকশন বৈশিষ্ট্য ব্যবহার করি। যদি এটি অনুশীলনে একটি সমস্যা হয়ে দাঁড়ায়, আমরা এটিকে সুইফটে যুক্ত করার বিষয়ে তদন্ত করতে পারি, তবে আমরা বর্তমানে মনে করি না যে এটি নিকটবর্তী মেয়াদে সমাধানের জন্য যথেষ্ট হবে।

সারসংক্ষেপ এবং উপসংহার

আমরা এই দিকটি সম্পর্কে ভাল অনুভব করি এবং মনে করি যে এই কাজের বেশ কয়েকটি আকর্ষণীয় দিক রয়েছে: এটি দুর্দান্ত যে সুইফ্ট কম্পাইলার বা ভাষাতে পাইথন নির্দিষ্ট পরিবর্তন নেই। আমরা পাইথন-স্বাধীন ভাষার বৈশিষ্ট্যগুলি রচনা করে সুইফটে লেখা একটি লাইব্রেরির মাধ্যমে পাইথন আন্তঃকার্যযোগ্যতা অর্জন করতে সক্ষম। আমরা বিশ্বাস করি যে অন্যান্য সম্প্রদায়গুলি অন্যান্য সম্প্রদায়ের জন্য গুরুত্বপূর্ণ (যেমন জাভাস্ক্রিপ্ট, রুবি, ইত্যাদি) গতিশীল ভাষাগুলির সাথে (এবং তাদের রানটাইম) সরাসরি সংহত করার জন্য একই বৈশিষ্ট্য সেট তৈরি করতে সক্ষম হবে।

এই কাজের আরেকটি আকর্ষণীয় দিক হল পাইথন সমর্থন অন্যান্য টেনসরফ্লো এবং স্বয়ংক্রিয় পার্থক্য লজিক থেকে সম্পূর্ণ স্বাধীন যা আমরা TensorFlow-এর জন্য Swift-এর অংশ হিসেবে তৈরি করছি। এটি সুইফ্ট ইকোসিস্টেমের একটি সাধারণভাবে উপযোগী এক্সটেনশন যা একা দাঁড়াতে পারে, সার্ভার সাইড ডেভেলপমেন্টের জন্য উপযোগী বা বিদ্যমান পাইথন এপিআই-এর সাথে ইন্টারঅপারেশন করতে চায়।